/*
 * Copyright (C) 2008,2009,2010,2011  Paulo Cesar Pereira de Andrade.
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * Authors:
 *	Paulo Cesar Pereira de Andrade
 */

/*
 * Conditions that must be checked:
 * o change of vm stack type/value:
 *	if (setting to a pointer)
 *		set_value(), set_type()
 *	else
 *		set_type(), set_value()
 *   it must be done in this order because since the garbage collector
 *   only stops the thread to check the vm stack, and it can happen at
 *   any moment, that order ensures that:
 *	o if current type must be marked, a valid pointer must be in the value
 *	  field
 *	o if current type is not marked, the value field may or may not be a
 *	  pointer
 *    since new objects are in thread_self->obj, setting the stack type/value
 *    can be done concurrently with gc, as it will block if gc is running when
 *    setting thread_self->obj to a newer value
 *      Note that if the stack value is marked, the stack type is not used,
 *    but the proper object type is checked; so, as long as it is a pointer,
 *    there is no problem in calling gc_mark() on an already marked object.
 *
 * o when a value that may exist only in the vm stack is loaded, and the
 *   stack slot is invalidated (by pop, or other change to thread_self->esp),
 *   it must be ensured that thread_self->r0 points to a gc reachable value,
 *   either by setting thread_self->obj to point to it, or for mp objects,
 *   calling mp*_set() on the thr_* "register" mp objects, and setting r0.v.o
 *   to point to it, as well as the type to a "register" mp type
 */

#include "exl.h"

#include <signal.h>

#define r0			thread_self->r0
#define ss			thread_self->ess
#define bp			thread_self->ebp
#define sp			thread_self->esp
#define obj			thread_self->obj
#define ret			thread_self->ret
#define flt			thread_self->flt
#define evalue			thread_self->evalue

/*
 * Prototypes
 */
static void
vm_signal_handler(int signo);

static void
load_pointer(eobject_t *pointer);

static void
load_object_type(eobject_t object, eint32_t type);

static void
load_value(evalue_t *value);

static void
load_value_type(evalue_t *value, eint32_t type);

static ehashentry_t *
hash_test(ehashtable_t *hash, ehashentry_t *test, evalue_t *name);

static ehashentry_t *
hash_test_create(ehashtable_t *hash, ehashentry_t *test, evalue_t *name);

static void
load_entry(ehashentry_t *entry);

static void
load_vector(eint32_t offset);

static eint32_t
get_offset(void);

static eint32_t
get_vector_offset(eint32_t length);

static void
store_object_type(eobject_t object, eint32_t type);

static void
store_value_type(evalue_t *value, eint32_t type);

static void
hash_store(ehashtable_t *hash, ehashentry_t *entry);

static void
store_vector_void(evalue_t *value, eint32_t offset);

static void
store_vector_int(evalue_t *value, eint32_t offset);

static void
store_vector_float(evalue_t *value, eint32_t offset);

static void
store_vector_mpz(evalue_t *value, eint32_t offset);

static void
store_vector_mpq(evalue_t *value, eint32_t offset);

static void
store_vector_mpr(evalue_t *value, eint32_t offset);

static void
store_vector_cdd(evalue_t *value, eint32_t offset);

static void
store_vector_cqq(evalue_t *value, eint32_t offset);

static void
store_vector_mpc(evalue_t *value, eint32_t offset);

static void
store_vector_object(evalue_t *value, eint32_t offset);

static void
store_vector(evalue_t *vector, eint32_t offset);

static void
coerce(eint32_t type);

static void
shift_raise(eint32_t real) noreturn;

static eint32_t
get_shift(eint32_t real);

static eint32_t
get_offset_value(evalue_t *value);

static eint32_t
get_offset_safe(void);

/*
 * Initialization
 */
#if HAVE_THREAD
static pthread_cond_t	count_cond;
static pthread_mutex_t	count_mutex;
#endif

/*
 * Implementation
 */
void
init_vm(void)
{
#if HAVE_THREAD
    pthread_cond_init(&count_cond, null);
    emutex_init(&count_mutex);
#endif
    /*
     * SIGFPE and SIGSEGV are (or should be) sent to the thread causing it
     * other signals are (or may be) sent to random threads
     */
    signal(SIGFPE, vm_signal_handler);
    signal(SIGSEGV, vm_signal_handler);
}

static void
vm_signal_handler(int signo)
{
    switch (signo) {
	case SIGFPE:
	    thread_self->except = except_floating_point_error;
	    break;
	case SIGSEGV:
	    thread_self->except = except_segmentation_violation;
	    break;
	default:
	    write(STDERR_FILENO, "unexpected signal\n", 18);
	    _exit(EXIT_FAILURE);
    }
#if JITVM
    /* while information in the stack */
    esearch_instruction_pointer();
#endif
    siglongjmp(thread_self->env, 1);
}

#if JITVM && DEBUG
void
evm_abort(void)
{
    esearch_instruction_pointer();
    eabort(thread_self->eip, "unexpected jit condition");
}
#endif

void
evm_raise(eint32_t exception)
{
    r0.t = t_int;
    r0.v.i = thread_self->except = exception;
#if JITVM
    /* while information in the stack */
    esearch_instruction_pointer();
#endif
    siglongjmp(thread_self->env, 1);
}

int
evm_float_zero_p(void)
{
    return (r0.v.d == 0.0);
}

void
evm_ll(eint32_t offset)
{
    r0.v.o = els[offset];
    if ((r0.t = eobject_type(r0.v.o)) == t_cdd)
	r0.v.cdd = *(ecdd_t *)r0.v.o;
}

static void
load_pointer(eobject_t *pointer)
{
    const eobject_t	value = *pointer;
    if (value) {
	const eint32_t	type = eobject_type(value);
	switch (type) {
	    case t_int:
		r0.t = t_int;
		r0.v.i = *(eint_t *)value;
		break;
	    case t_float:
		r0.t = t_float;
		r0.v.d = *(efloat_t *)value;
		break;
	    case t_cdd:
		r0.t = t_cdd;
		r0.v.cdd = *(ecdd_t *)value;
		break;
	    case t_globalref:
		r0.t = t_globalref;
		r0.v.o = *(eobject_t *)value;
		break;
	    default:
		r0.v.o = value;
		r0.t = type;
		break;
	}
    }
    else {
	r0.t = t_void;
	r0.v.o = null;
    }
}

void
evm_ld(eint32_t offset)
{
    load_pointer(eds + offset);
}

static void
load_object_type(eobject_t object, eint32_t type)
{
    switch (type) {
	case t_int8:
	    r0.t = t_int;
	    r0.v.i = *(eint8_t *)object;
	    break;
	case t_uint8:
	    r0.t = t_int;
	    r0.v.i = *(euint8_t *)object;
	    break;
	case t_int16:
	    r0.t = t_int;
	    r0.v.i = *(eint16_t *)object;
	    break;
	case t_uint16:
	    r0.t = t_int;
	    r0.v.i = *(euint16_t *)object;
	    break;
	case t_int32:
	    r0.t = t_int;
	    r0.v.i = *(eint32_t *)object;
	    break;
	case t_uint32:
	    r0.t = t_int;
	    r0.v.i = *(euint32_t *)object;
	    break;
	case t_int:
	    r0.t = t_int;
	    r0.v.i = *(eint_t *)object;
	    break;
	case t_uint:
	    r0.t = t_int;
	    r0.v.i = *(eint_t *)object;
	    if (unlikely(r0.v.i < 0)) {
		empz_set_u(thr_zr, r0.v.i);
		set_rz();
	    }
	    break;
	case t_float32:
	    r0.t = t_float;
	    r0.v.d = *(efloat32_t *)object;
	    break;
	case t_float:
	    r0.t = t_float;
	    r0.v.d = *(efloat_t *)object;
	    break;
	default:
	    load_pointer(object);
	    break;
    }
}

void
evm_ldt(eint32_t offset, eint32_t type)
{
    load_object_type(eds[offset], type);
}

static void
load_value(evalue_t *value)
{
    switch (value->t) {
	case t_void:
	    r0.t = t_void;
	    r0.v.o = null;
	    break;
	case t_int:
	    r0.t = t_int;
	    r0.v.i = value->v.i;
	    break;
	case t_float:
	    r0.t = t_float;
	    r0.v.d = value->v.d;
	    break;
	case t_cdd:
	    r0.t = t_cdd;
	    r0.v.cdd = value->v.cdd;
	    break;
	case t_globalref:
	    r0.t = t_globalref;
	    r0.v.o = value->v.o;
	    break;
	default:
	    r0.v.o = value->v.o;
	    r0.t = value->t;
	    break;
    }
}

void
evm_lb(eint32_t offset)
{
    load_value(bp + offset);
}

static void
load_value_type(evalue_t *value, eint32_t type)
{
    switch (type) {
	case t_int8:
	    r0.t = t_int;
	    r0.v.i = value->v.i8;
	    break;
	case t_uint8:
	    r0.t = t_int;
	    r0.v.i = value->v.u8;
	    break;
	case t_int16:
	    r0.t = t_int;
	    r0.v.i = value->v.i16;
	    break;
	case t_uint16:
	    r0.t = t_int;
	    r0.v.i = value->v.u16;
	    break;
	case t_int32:
	    r0.t = t_int;
	    r0.v.i = value->v.i32;
	    break;
	case t_uint32:
	    r0.t = t_int;
	    r0.v.i = value->v.u32;
	    break;
	case t_int:
	    r0.t = t_int;
	    r0.v.i = value->v.i;
	    break;
	case t_uint:
	    r0.t = t_int;
	    r0.v.i = value->v.i;
	    if (unlikely(r0.v.i < 0)) {
		empz_set_u(thr_zr, r0.v.i);
		set_rz();
	    }
	    break;
	case t_float32:
	    r0.t = t_float;
	    r0.v.d = value->v.f32;
	    break;
	case t_float:
	    r0.t = t_float;
	    r0.v.d = value->v.d;
	    break;
	case t_cdd:
	    r0.t = t_cdd;
	    r0.v.cdd = value->v.cdd;
	    break;
	default:
	    r0.v.o = value->v.o;
	    r0.t = value->t;
	    break;
    }
}

void
evm_lbt(eint32_t offset, eint32_t type)
{
    load_value_type(bp + offset, type);
}

void
evm_ls(eint32_t offset)
{
    load_value(sp + offset);
}

static ehashentry_t *
hash_test(ehashtable_t *hash, ehashentry_t *test, evalue_t *name)
{
    /* test mp register types also, as r0 is a valid name argument */
    switch (name->t) {
	case t_void:
	    /* entry with null key is not allowed */
	    test->nt = t_void;
	    test->nv.o = null;
	    return (null);
	case t_int:
	    test->nt = t_int;
	    test->nv.i = name->v.i;
	    break;
	case t_float:
	    test->nt = t_float;
	    test->nv.d = name->v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    test->nt = t_mpz;
	    test->nv.z = name->v.mpz;
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    test->nt = t_mpq;
	    test->nv.q = name->v.mpq;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    test->nt = t_mpr;
	    test->nv.r = name->v.mpr;
	    break;
	case t_cdd:
	    test->nt = t_cdd;
	    test->nv.dd = name->v.cdd;
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    test->nt = t_cqq;
	    test->nv.qq = name->v.cqq;
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    test->nt = t_mpc;
	    test->nv.c = name->v.mpc;
	    break;
	default:
	    test->nt = name->t & ~t_const;
	    test->nv.o = name->v.o;
	    break;
    }
    ekey_hashentry(test);
    return (eget_hashentry(hash, test));
}

static ehashentry_t *
hash_test_create(ehashtable_t *hash, ehashentry_t *test, evalue_t *name)
{
    ehashentry_t	*entry;
    entry = hash_test(hash, test, name);
    if (entry == null) {
	if (test->nt == t_void)
	    return (null);
	enew_object(&obj, t_hashentry, sizeof(ehashentry_t));
	entry = obj;
	switch (entry->nt = test->nt) {
	    case t_int:
		entry->nv.i = test->nv.i;
		break;
	    case t_float:
		entry->nv.d = test->nv.d;
		break;
	    case t_mpz:
		enew_mpz(&entry->nv.o, test->nv.z);
		break;
	    case t_mpq:
		enew_mpq(&entry->nv.o, test->nv.q);
		break;
	    case t_mpr:
		enew_mpr(&entry->nv.o, test->nv.r);
		break;
	    case t_cdd:
		entry->nv.dd = test->nv.dd;
		break;
	    case t_cqq:
		enew_cqq(&entry->nv.o, test->nv.qq);
		break;
	    case t_mpc:
		enew_mpc(&entry->nv.o, test->nv.c);
		break;
	    case t_string:
		/* if modifiable string (only strings are hashed by memory
		 * contents, and numbers are duplicated) */
		enew_vector(&entry->nv.v, t_uint8, test->nv.v->length, 1);
		memcpy(entry->nv.v->v.u8, test->nv.v->v.u8, test->nv.v->length);
		break;
	    default:
		entry->nv.o = test->nv.o;
		break;
	}
	entry->key = test->key;
	eput_hashentry(hash, entry);
    }
    return (entry);
}

static void
load_entry(ehashentry_t *entry)
{
    switch (entry->vt) {
	case t_int:
	    r0.t = t_int;
	    r0.v.i = entry->vv.i;
	    break;
	case t_float:
	    r0.t = t_float;
	    r0.v.d = entry->vv.d;
	    break;
	case t_cdd:
	    r0.t = t_cdd;
	    r0.v.cdd = entry->vv.dd;
	    break;
	case t_globalref:
	    r0.t = t_globalref;
	    r0.v.o = entry->vv.v->v.ptr;
	    break;
	default:
	    r0.v.o = entry->vv.o;
	    r0.t = entry->vt;
	    break;
    }
}

void
evm_lh(void)
{
    ehashentry_t	 test;
    ehashentry_t	*entry;
    if (unlikely(sp[-1].t != t_hashtable))
	evm_raise(except_type_mismatch);
    if ((entry = hash_test(sp[-1].v.o, &test, &r0)))
	load_entry(entry);
    else {
	r0.t = t_void;
	r0.v.o = null;
    }
    --sp;
}

void
evm_lhref(eint32_t arg)
{
    ehashentry_t	 test;
    ehashentry_t	*entry;
    ehashtable_t	*table;
    if (unlikely(sp[-1].t != t_hashtable))
	evm_raise(except_type_mismatch);
    table = sp[-1].v.o;
    if ((entry = hash_test_create(table, &test, &r0)))
	load_entry(entry);
    else
	/* something like hash[null]++; */
	evm_raise(except_null_dereference);
    if (arg == 1) {
	++sp;
	sp[-1].v.href.table = table;
	sp[-1].v.href.entry = entry;
	sp[-1].t = t_hashref;
	evm_store_value_push(sp - 2);
    }
    else {
	sp[-1].v.href.table = table;
	sp[-1].v.href.entry = entry;
	sp[-1].t = t_hashref;
	if (arg) {
	    ++sp;
	    evm_store_value_push(sp - 1);
	}
    }
}

static void
load_vector(eint32_t offset)
{
    switch (r0.t & ~(t_const|t_vector)) {
	case t_int8:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppi8)[offset];
	    break;
	case t_uint8:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppu8)[offset];
	    break;
	case t_int16:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppi16)[offset];
	    break;
	case t_uint16:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppu16)[offset];
	    break;
	case t_int32:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppi32)[offset];
	    break;
	case t_uint32:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppu32)[offset];
	    break;
	case t_int:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppi64)[offset];
	    break;
	case t_uint:
	    r0.t = t_int;
	    r0.v.i = (*r0.v.ppu64)[offset];
	    if (unlikely(r0.v.i < 0)) {
		empz_set_u(thr_zr, r0.v.i);
		set_rz();
	    }
	    break;
	case t_float32:
	    r0.t = t_float;
	    r0.v.d = (*r0.v.ppf32)[offset];
	    break;
	case t_float:
	    r0.t = t_float;
	    r0.v.d = (*r0.v.ppf64)[offset];
	    break;
	default:
	    load_pointer((*r0.v.v) + offset);
	    break;
    }
}

static eint32_t
get_offset(void)
{
    eint32_t	offset;
    switch (r0.t) {
	case t_void:
	    offset = 0;
	    break;
	case t_int:
	    if ((euint_t)r0.v.i > most_positive_fix32)
		evm_raise(except_out_of_bounds);
	    offset = r0.v.i;
	    break;
	case t_float:
	    if (r0.v.d >= 0 && r0.v.d <= most_positive_fix32)
		offset = r0.v.d;
	    else
		evm_raise(except_out_of_bounds);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_raise(except_out_of_bounds);
	case t_mpq:		case t_shq:		case t_rgq:
	    mpz_set_q(thr_zr, r0.v.mpq);
	    if (mpz_fits_sint_p(thr_zr))
		offset = mpz_get_si(thr_zr);
	    else
		evm_raise(except_out_of_bounds);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    if (mpfr_fits_sint_p(r0.v.mpr, GMP_RNDZ))
		offset = empr_get_i(r0.v.mpr);
	    else
		evm_raise(except_out_of_bounds);
	    break;
	default:
	    evm_raise(except_not_an_integer);
    }
    return (offset);
}

static eint32_t
get_vector_offset(eint32_t length)
{
    eint32_t	temp;
    eint32_t	offset;
    offset = get_offset();
    temp = sp[-length].t;
    if (!evector_type_p(temp))
	evm_raise(except_type_mismatch);
    r0.v.o = sp[-length].v.o; 
    r0.t = temp;
    if (length != r0.v.V->rank)
	evm_raise(except_type_mismatch);
    if (offset >= r0.v.V->dims[length - 1].dim)
	evm_raise(except_out_of_bounds);
    for (temp = length - 1; temp; --temp, --sp)
	offset += sp[-1].v.i;
#if DEBUG
    if (unlikely((euint32_t)offset >= r0.v.V->length))
	evm_raise(except_out_of_bounds);
#endif
    return (offset);
}

void
evm_lv(eint32_t length)
{
    load_vector(get_vector_offset(length));
    --sp;
}

void
evm_lvi(eint32_t offset)
{
    if (!evector_type_p(r0.t))
	evm_raise(except_type_mismatch);
    if (unlikely((euint32_t)offset >= r0.v.V->length))
	evm_raise(except_out_of_bounds);
    load_vector(offset);
}

void
evm_lvref(eint32_t length, eint32_t arg)
{
    eint32_t	 offset;
    evector_t	*vector;
    vector = sp[-length].v.o;
    offset = get_vector_offset(length);
    load_vector(offset);
    if (arg == 1) {
	++sp;
	sp[-1].v.vref.vector = vector;
	sp[-1].v.vref.offset = offset;
	sp[-1].t = t_vectorref;
	evm_store_value_push(sp - 2);
    }
    else {
	sp[-1].v.vref.vector = vector;
	sp[-1].v.vref.offset = offset;
	sp[-1].t = t_vectorref;
	if (arg) {
	    ++sp;
	    evm_store_value_push(sp - 1);
	}
    }
}

void
evm_match_inheritance(eint32_t base, eint32_t type, eint32_t offset)
{
    eint32_t	length;
    /* object type doesn't match it's declared type,
     * do slow inheritance class data field check */
    if (type >= ets_idx || type <= elast_basic_type)
	evm_raise(except_type_mismatch);
    if (offset >= ets[type].size)
	evm_raise(except_type_mismatch);
    if (offset == 0)
	base = ets[type].fields[0].parent;
    else if ((length = ets[type].translate[offset]) == 0)
	evm_raise(except_type_mismatch);
    else if (ets[type].fields[length].offset != offset)
	evm_raise(except_type_mismatch);
    else
	base = ets[type].fields[length].parent;
    while (type != base) {
	if ((type = ets[type].super) == t_void)
	    evm_raise(except_type_mismatch);
    }
}

void
evm_lr(eint32_t base, eint32_t offset, eint32_t type)
{
    if (r0.t != base)
	evm_match_inheritance(base, r0.t, offset);
    load_object_type(r0.v.r + offset, type);
}

void
evm_lrref(eint32_t base, eint32_t offset, eint32_t type, eint32_t arg)
{
    eobject_t	record;
    if (r0.t != base)
	evm_match_inheritance(base, r0.t, offset);
    record = r0.v.o;
    load_object_type(r0.v.r + offset, type);
    if (arg == 1) {
	sp += 2;
	sp[-1].v.rref.record = record;
	sp[-1].v.rref.offset = offset;
	sp[-1].v.rref.type = type;
	sp[-1].t = t_recordref;
	evm_store_value_push(sp - 2);
    }
    else {
	++sp;
	sp[-1].v.rref.record = record;
	sp[-1].v.rref.offset = offset;
	sp[-1].v.rref.type = type;
	sp[-1].t = t_recordref;
	if (arg) {
	    ++sp;
	    evm_store_value_push(sp - 1);
	}
    }
}

void
evm_lc(eint32_t offset, eint32_t type)
{
    load_object_type(bp[-2].v.r + offset, type);
}

void
evm_lref(void)
{
    evalue_t	*p;
    eint32_t	 offset;
    switch (r0.t) {
	case t_anonref:		case t_globalref:
	    load_pointer(r0.v.o);
	    break;
	case t_localref:	case t_t_localref:
	    p = r0.v.loc->thread->ess + r0.v.loc->offset;
	    /* This takes advantage that vm state on the stack is
	     * of type t_void, but have a valid pointer. Every other
	     * usage of t_void as a true null pointer also has the
	     * pointer field as null. */
	    if (p >= r0.v.loc->thread->esp || (p->t == t_void && p->v.o))
		evm_raise(except_invalid_argument);
	    load_value_type(p, p->t);
	    break;
	case t_stackref:	case t_t_stackref:
	    p = r0.v.ref;
	    load_value_type(p, p->t);
	    break;
	default:
	    if (!(r0.t & t_pointer))
		evm_raise(except_type_mismatch);
	    offset = r0.v.V->offset;
	    r0.v.o = r0.v.V->v.ptr;
	    if (r0.t & t_vector) {
		r0.t &= ~t_pointer;
		load_vector(offset);
	    }
	    else
		load_object_type(r0.v.r + offset, r0.t & ~t_pointer);
	    break;
    }
}

void
evm_pdt(eint32_t offset)
{
    const eobject_t	value = eds[offset];
    const eint32_t	type = t_pointer | eobject_type(value);
    enew_pointer(&obj, type, value, 0);
    r0.v.o = obj;
    r0.t = type;
}

void
evm_pv(eint32_t length)
{
    const eint32_t	offset = get_vector_offset(length);
    /* r0.t changes in call to get_vector_offset() */
    const eint32_t	type = r0.t | t_pointer;
    enew_pointer(&obj, type, sp[-1].v.V, offset);
    r0.v.o = obj;
    r0.t = type;
    --sp;
}

void
evm_pvi(eint32_t offset)
{
    const eint32_t	type = r0.t | t_pointer;
    if (!evector_type_p(r0.t))
	evm_raise(except_type_mismatch);
    enew_pointer(&obj, type, r0.v.V, offset);
    r0.v.o = obj;
    r0.t = type;
}

void
evm_pr(eint32_t base, eint32_t offset, eint32_t type)
{
    if (r0.t != base)
	evm_match_inheritance(base, r0.t, offset);
    type |= t_pointer;
    enew_pointer(&obj, type, r0.v.o, offset);
    r0.v.o = obj;
    r0.t = type;
}

void
evm_pp(void)
{
    if (r0.t <= elast_basic_type)
	evm_raise(except_type_mismatch);
    enew_anonref(&obj, r0.v.o);
    r0.v.o = obj;
    r0.t = t_anonref;
}

void
evm_anon(eint32_t type, eint32_t size)
{
    enew_object(&obj, type, size);
    enew_anonref(&obj, obj);
    r0.v.o = obj;
    r0.t = t_anonref;
}

void
evm_store_int8(eint8_t *object)
{
    switch (r0.t) {
	case t_void:
	    *object = 0;
	    break;
	case t_int:
	    *object = r0.v.i;
	    break;
	case t_float:
	    *object = (eint32_t)r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    *object = empz_get_i(r0.v.mpz);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    *object = empq_get_i(r0.v.mpq);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    *object = empr_get_i(r0.v.mpr);
	    break;
	case t_cdd:
	    *object = ecdd_get_i(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    *object = ecqq_get_i(r0.v.cqq);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    *object = empc_get_i(r0.v.mpc);
	    break;
	default:
	    evm_raise(except_invalid_argument);
    }
}

void
evm_store_int16(eint16_t *object)
{
    switch (r0.t) {
	case t_void:
	    *object = 0;
	    break;
	case t_int:
	    *object = r0.v.i;
	    break;
	case t_float:
	    *object = (eint32_t)r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    *object = empz_get_i(r0.v.mpz);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    *object = empq_get_i(r0.v.mpq);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    *object = empr_get_i(r0.v.mpr);
	    break;
	case t_cdd:
	    *object = ecdd_get_i(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    *object = ecqq_get_i(r0.v.cqq);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    *object = empc_get_i(r0.v.mpc);
	    break;
	default:
	    evm_raise(except_invalid_argument);
    }
}

void
evm_store_int32(eint32_t *object)
{
    switch (r0.t) {
	case t_void:
	    *object = 0;
	    break;
	case t_int:
	    *object = r0.v.i;
	    break;
	case t_float:
	    *object = (eint32_t)r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    *object = empz_get_i(r0.v.mpz);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    *object = empq_get_i(r0.v.mpq);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    *object = empr_get_i(r0.v.mpr);
	    break;
	case t_cdd:
	    *object = ecdd_get_i(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    *object = ecqq_get_i(r0.v.cqq);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    *object = empc_get_i(r0.v.mpc);
	    break;
	default:
	    evm_raise(except_invalid_argument);
    }
}

void
evm_store_int64(eint_t *object)
{
    switch (r0.t) {
	case t_void:
	    *object = 0;
	    break;
	case t_int:
	    *object = r0.v.i;
	    break;
	case t_float:
	    *object = (eint_t)r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    *object = empz_get_i(r0.v.mpz);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    *object = empq_get_i(r0.v.mpq);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    *object = empr_get_i(r0.v.mpr);
	    break;
	case t_cdd:
	    *object = ecdd_get_i(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    *object = ecqq_get_i(r0.v.cqq);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    *object = empc_get_i(r0.v.mpc);
	    break;
	default:
	    evm_raise(except_invalid_argument);
    }
}

void
evm_store_float32(efloat32_t *object)
{
    switch (r0.t) {
	case t_void:
	    *object = 0.0;
	    break;
	case t_int:
	    *object = r0.v.i;
	    break;
	case t_float:
	    *object = r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    *object = empz_get_d(r0.v.mpz);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    *object = empq_get_d(r0.v.mpq);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    *object = empr_get_d(r0.v.mpr);
	    break;
	case t_cdd:
	    *object = ecdd_get_d(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    *object = ecqq_get_d(r0.v.cqq);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    *object = empc_get_d(r0.v.mpc);
	    break;
	default:
	    evm_raise(except_invalid_argument);
    }
}

void
evm_store_float64(efloat_t *object)
{
    switch (r0.t) {
	case t_void:
	    *object = 0.0;
	    break;
	case t_int:
	    *object = r0.v.i;
	    break;
	case t_float:
	    *object = r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    *object = empz_get_d(r0.v.mpz);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    *object = empq_get_d(r0.v.mpq);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    *object = empr_get_d(r0.v.mpr);
	    break;
	case t_cdd:
	    *object = ecdd_get_d(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    *object = ecqq_get_d(r0.v.cqq);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    *object = empc_get_d(r0.v.mpc);
	    break;
	default:
	    evm_raise(except_invalid_argument);
    }
}

void
evm_store_pointer_int(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_int))
	*(eint_t *)*pointer = r0.v.i;
    else
	enew_integer(pointer, r0.v.i);
}

void
evm_store_pointer_float(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_float))
	*(efloat_t *)*pointer = r0.v.d;
    else
	enew_float(pointer, r0.v.d);
}

void
evm_store_pointer_mpz(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_mpz))
	empz_set((empz_t)*pointer, r0.v.mpz);
    else
	enew_mpz(pointer, r0.v.mpz);
}

void
evm_store_pointer_mpq(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_mpq))
	empq_set((empq_t)*pointer, r0.v.mpq);
    else
	enew_mpq(pointer, r0.v.mpq);
}

void
evm_store_pointer_mpr(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_mpr))
	empr_set((empr_t)*pointer, r0.v.mpr);
    else
	enew_mpr(pointer, r0.v.mpr);
}

void
evm_store_pointer_cdd(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_cdd))
	*(ecdd_t *)*pointer = r0.v.cdd;
    else
	enew_cdd(pointer, r0.v.cdd);
}

void
evm_store_pointer_cqq(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_cqq))
	ecqq_set((ecqq_t)*pointer, r0.v.cqq);
    else
	enew_cqq(pointer, r0.v.cqq);
}

void
evm_store_pointer_mpc(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_mpc))
	empc_set((empc_t)*pointer, r0.v.mpc);
    else
	enew_mpc(pointer, r0.v.mpc);
}

void
evm_store_pointer_globalref(eobject_t *pointer)
{
    if (likely(*pointer && eobject_type(*pointer) == t_globalref))
	*(eobject_t *)*pointer = r0.v.o;
    else
	enew_globalref(pointer, r0.v.o);
}

void
evm_store_pointer(eobject_t *pointer)
{
    switch (r0.t) {
	case t_int:
	    evm_store_pointer_int(pointer);
	    break;
	case t_float:
	    evm_store_pointer_float(pointer);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_store_pointer_mpz(pointer);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_store_pointer_mpq(pointer);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_store_pointer_mpr(pointer);
	    break;
	case t_cdd:
	    evm_store_pointer_cdd(pointer);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_store_pointer_cqq(pointer);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_store_pointer_mpc(pointer);
	    break;
	case t_globalref:
	    evm_store_pointer_globalref(pointer);
	    break;
	case t_stackref:
	    enew_localref(pointer, r0.v.ref - ss);
	    break;
	case t_t_stackref:
	    enew_t_localref(pointer, r0.v.ref - ss);
	    break;
	default:
	    *pointer = r0.v.o;
	    break;
    }
}

void
evm_sd(eint32_t offset)
{
    evm_store_pointer(eds + offset);
}

static void
store_object_type(eobject_t object, eint32_t type)
{
    switch (type) {
	case t_int8:		case t_uint8:
	    evm_store_int8(object);
	    break;
	case t_int16:		case t_uint16:
	    evm_store_int16(object);
	    break;
	case t_int32:		case t_uint32:
	    evm_store_int32(object);
	    break;
	case t_int:		case t_uint:
	    evm_store_int64(object);
	    break;
	case t_float32:
	    evm_store_float32(object);
	    break;
	case t_float:
	    evm_store_float64(object);
	    break;
	default:
	    evm_store_pointer(object);
	    break;
    }
}

void
evm_sdt(eint32_t offset, eint32_t type)
{
    store_object_type(eds[offset], type);
}

void
evm_store_value(evalue_t *value)
{
    switch (r0.t) {
	case t_int:
	    value->t = t_int;
	    value->v.i = r0.v.i;
	    break;
	case t_float:
	    value->t = t_float;
	    value->v.d = r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (value->t == t_mpz)
		empz_set(value->v.mpz, r0.v.mpz);
	    else {
		enew_mpz(&obj, r0.v.mpz);
		value->v.o = obj;
		value->t = t_mpz;
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (value->t == t_mpq)
		empq_set(value->v.mpq, r0.v.mpq);
	    else {
		enew_mpq(&obj, r0.v.mpq);
		value->v.o = obj;
		value->t = t_mpq;
	    }
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    if (value->t == t_mpr)
		empr_set(value->v.mpr, r0.v.mpr);
	    else {
		enew_mpr(&obj, r0.v.mpr);
		value->v.o = obj;
		value->t = t_mpr;
	    }
	    break;
	case t_cdd:
	    value->t = t_cdd;
	    value->v.cdd = r0.v.cdd;
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (value->t == t_cqq)
		ecqq_set(value->v.cqq, r0.v.cqq);
	    else {
		enew_cqq(&obj, r0.v.cqq);
		value->v.o = obj;
		value->t = t_cqq;
	    }
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    if (value->t == t_mpc)
		empc_set(value->v.mpc, r0.v.mpc);
	    else {
		enew_mpc(&obj, r0.v.mpc);
		value->v.o = obj;
		value->t = t_mpc;
	    }
	    break;
	case t_globalref:
	    value->t = t_globalref;
	    value->v.o = r0.v.o;
	    break;
	default:
	    value->v.o = r0.v.o;
	    value->t = r0.t;
	    break;
    }
}

void
evm_sb(eint32_t offset)
{
    evm_store_value(bp + offset);
}

static void
store_value_type(evalue_t *value, eint32_t type)
{
    switch (type) {
	case t_int8:		case t_uint8:
	    evm_store_int8(&value->v.i8);
	    break;
	case t_int16:		case t_uint16:
	    evm_store_int16(&value->v.i16);
	    break;
	case t_int32:		case t_uint32:
	    evm_store_int32(&value->v.i32);
	    break;
	case t_int:		case t_uint:
	    evm_store_int64(&value->v.i);
	    break;
	case t_float32:
	    evm_store_float32(&value->v.f32);
	    break;
	case t_float:
	    evm_store_float64(&value->v.d);
	    break;
	default:
	    evm_store_value(value);
	    break;
    }
}

void
evm_sbt(eint32_t offset, eint32_t type)
{
    store_value_type(bp + offset, type);
}

/* not a variable but a temporary stack value, only difference from
 * evm_store_value() is handling of multi precision objects */
void
evm_store_value_push(evalue_t *value)
{
    switch (r0.t) {
	case t_int:
	    value->t = t_int;
	    value->v.i = r0.v.i;
	    break;
	case t_float:
	    value->t = t_float;
	    value->v.d = r0.v.d;
	    break;
	case t_mpz:
	    value->v.mpz = r0.v.mpz;
	    value->t = t_mpz;
	    break;
	case t_shz:		case t_rgz:
	    if (value->t == t_shz)
		empz_set(value->v.mpz, r0.v.mpz);
	    else
		eget_mpz(r0.v.mpz, value - ss);
	    break;
	case t_mpq:
	    value->v.mpq = r0.v.mpq;
	    value->t = t_mpq;
	    break;
	case t_shq:		case t_rgq:
	    if (value->t == t_shq)
		empq_set(value->v.mpq, r0.v.mpq);
	    else
		eget_mpq(r0.v.mpq, value - ss);
	    break;
	case t_mpr:
	    value->v.mpr = r0.v.mpr;
	    value->t = t_mpr;
	    break;
	case t_shr:		case t_rgr:
	    if (value->t == t_shr)
		empr_set(value->v.mpr, r0.v.mpr);
	    else
		eget_mpr(r0.v.mpr, value - ss);
	    break;
	case t_cdd:
	    value->t = t_cdd;
	    value->v.cdd = r0.v.cdd;
	    break;
	case t_cqq:
	    value->v.cqq = r0.v.cqq;
	    value->t = t_cqq;
	    break;
	case t_sqq:		case t_rqq:
	    if (value->t == t_sqq)
		ecqq_set(value->v.cqq, r0.v.cqq);
	    else
		eget_cqq(r0.v.cqq, value - ss);
	    break;
	case t_mpc:
	    value->v.mpc = r0.v.mpc;
	    value->t = t_mpc;
	    break;
	case t_shc:		case t_rgc:
	    if (value->t == t_shc)
		empc_set(value->v.mpc, r0.v.mpc);
	    else
		eget_mpc(r0.v.mpc, value - ss);
	    break;
	default:
	    value->v.o = r0.v.o;
	    value->t = r0.t;
	    break;
    }
}

/* like evm_store_value, but extra version to avoid the need to zero
 * out unbound stack offsets just to ensure type tests fail, that is,
 * it is creating a local variable, not changing it; this is required
 * to avoid possible issues with another thread garbage collecting
 * the object (FIXME actually, it should be safe, as the stack is
 * incremented before actually checking what is there) */
void
evm_store_value_copy(evalue_t *value)
{
    switch (r0.t) {
	case t_int:
	    value->t = t_int;
	    value->v.i = r0.v.i;
	    break;
	case t_float:
	    value->t = t_float;
	    value->v.d = r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    enew_mpz(&obj, r0.v.mpz);
	    value->v.o = obj;
	    value->t = t_mpz;
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    enew_mpq(&obj, r0.v.mpq);
	    value->v.o = obj;
	    value->t = t_mpq;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    enew_mpr(&obj, r0.v.mpr);
	    value->v.o = obj;
	    value->t = t_mpr;
	    break;
	case t_cdd:
	    value->t = t_cdd;
	    value->v.cdd = r0.v.cdd;
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    enew_cqq(&obj, r0.v.cqq);
	    value->v.o = obj;
	    value->t = t_cqq;
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    enew_mpc(&obj, r0.v.mpc);
	    value->v.o = obj;
	    value->t = t_mpc;
	    break;
	case t_globalref:
	    value->t = t_globalref;
	    value->v.o = r0.v.o;
	    break;
	default:
	    value->v.o = r0.v.o;
	    value->t = r0.t;
	    break;
    }
}

void
evm_ss(eint32_t offset)
{
    evm_store_value_push(sp + offset);
}

void
evm_sst(eint32_t offset, eint32_t type)
{
    sp[offset].t = type;
    store_value_type(sp + offset, type);
}

void
evm_ssv(eint32_t offset)
{
    evm_store_value(sp + offset);
}

static void
hash_store(ehashtable_t *hash, ehashentry_t *entry)
{
    if (unlikely(entry == null))
	evm_raise(except_null_dereference);
    switch (r0.t) {
	case t_int:
	    entry->vt = t_int;
	    entry->vv.i = r0.v.i;
	    break;
	case t_float:
	    entry->vt = t_float;
	    entry->vv.d = r0.v.d;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (entry->vt == t_mpz)
		empz_set(entry->vv.z, r0.v.mpz);
	    else {
		enew_mpz(&obj, r0.v.mpz);
		entry->vv.z = obj;
		entry->vt = t_mpz;
	    }
	    break;
	case t_mpq:		case t_shq: 		case t_rgq:
	    if (entry->vt == t_mpq)
		empq_set(entry->vv.q, r0.v.mpq);
	    else {
		enew_mpq(&obj, r0.v.mpq);
		entry->vv.q = obj;
		entry->vt = t_mpq;
	    }
	    break;
	case t_mpr:		case t_shr: 		case t_rgr:
	    if (entry->vt == t_mpr)
		empr_set(entry->vv.r, r0.v.mpr);
	    else {
		enew_mpr(&obj, r0.v.mpr);
		entry->vv.r = obj;
		entry->vt = t_mpr;
	    }
	    break;
	case t_cdd:
	    entry->vt = t_cdd;
	    entry->vv.dd = r0.v.cdd;
	    break;
	case t_cqq:		case t_sqq: 		case t_rqq:
	    if (entry->vt == t_cqq)
		cqq_set(entry->vv.qq, r0.v.cqq);
	    else {
		enew_cqq(&obj, r0.v.cqq);
		entry->vv.qq = obj;
		entry->vt = t_cqq;
	    }
	    break;
	case t_mpc:		case t_shc: 		case t_rgc:
	    if (entry->vt == t_mpc)
		empc_set(entry->vv.c, r0.v.mpc);
	    else {
		enew_mpc(&obj, r0.v.mpc);
		entry->vv.c = obj;
		entry->vt = t_mpc;
	    }
	    break;
	case t_globalref:
	    if (entry->vt == t_globalref)
		entry->vv.v->v.u8 = r0.v.o;
	    else {
		enew_globalref(&entry->vv.o, r0.v.o);
		entry->vt = t_globalref;
	    }
	    break;
	case t_stackref:
	    enew_localref(&entry->vv.o, r0.v.ref - ss);
	    entry->vt = t_localref;
	    break;
	case t_t_stackref:
	    enew_t_localref(&entry->vv.o, r0.v.ref - ss);
	    entry->vt = t_t_localref;
	    break;
	default:
	    entry->vv.o = r0.v.o;
	    entry->vt = r0.t;
	    break;
    }
}

void
evm_sh(void)
{
    ehashentry_t test;
    if (unlikely(sp[-2].t != t_hashtable))
	evm_raise(except_type_mismatch);
#if 1	/* until r0 is inspectable */
    switch (r0.t) {
	case t_int:		case t_float:
	case t_rgz:		case t_shz:
	case t_rgq:		case t_shq:
	case t_rgr:		case t_shr:
	case t_cdd:
	case t_rqq:		case t_sqq:
	case t_rgc:		case t_shc:
	case t_globalref:
	case t_stackref:	case t_t_stackref:
	    v_push(obj);
	    break;
	default:
	    v_push(r0.v.o);
	    break;
    }
#endif
    hash_store(sp[-2].v.o, hash_test_create(sp[-2].v.o, &test, sp - 1));
#if 1	/* until r0 is inspectable */
    v_dec();
#endif
    sp -= 2;
}

void
evm_shref(eint32_t arg)
{
    assert(sp[-1].t == t_hashref);
    hash_store(sp[-1].v.href.table, sp[-1].v.href.entry);
    if (arg) {
	load_value(sp - 2);
	sp -= 2;
    }
    else
	--sp;
}

static void
store_vector_void(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = 0;
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = 0;
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = 0;
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = 0;
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = 0.0;
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = 0.0;
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    (*value->v.v)[offset] = null;
	    break;
    }
}

static void
store_vector_int(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = r0.v.i;
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = r0.v.i;
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = r0.v.i;
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = r0.v.i;
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = r0.v.i;
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = r0.v.i;
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_int((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_float(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = (eint_t)r0.v.d;
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = (eint_t)r0.v.d;
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = (eint_t)r0.v.d;
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = (eint_t)r0.v.d;
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = r0.v.d;
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = r0.v.d;
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_float((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_mpz(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = empz_get_i(r0.v.mpz);
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = empz_get_i(r0.v.mpz);
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = empz_get_i(r0.v.mpz);
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = empz_get_i(r0.v.mpz);
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = empz_get_d(r0.v.mpz);
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = empz_get_d(r0.v.mpz);
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_mpz((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_mpq(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = empq_get_i(r0.v.mpq);
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = empq_get_i(r0.v.mpq);
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = empq_get_i(r0.v.mpq);
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = empq_get_i(r0.v.mpq);
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = empq_get_d(r0.v.mpq);
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = empq_get_d(r0.v.mpq);
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_mpq((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_mpr(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = empr_get_i(r0.v.mpr);
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = empr_get_i(r0.v.mpr);
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = empr_get_i(r0.v.mpr);
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = empr_get_i(r0.v.mpr);
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = empr_get_d(r0.v.mpr);
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = empr_get_d(r0.v.mpr);
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_mpr((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_cdd(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = ecdd_get_i(r0.v.cdd);
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = ecdd_get_i(r0.v.cdd);
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = ecdd_get_i(r0.v.cdd);
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = ecdd_get_i(r0.v.cdd);
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = ecdd_get_d(r0.v.cdd);
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = ecdd_get_d(r0.v.cdd);
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_cdd((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_cqq(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = ecqq_get_i(r0.v.cqq);
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = ecqq_get_i(r0.v.cqq);
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = ecqq_get_i(r0.v.cqq);
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = ecqq_get_i(r0.v.cqq);
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = ecqq_get_d(r0.v.cqq);
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = ecqq_get_d(r0.v.cqq);
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_cqq((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_mpc(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	    (*value->v.ppi8)[offset] = empc_get_i(r0.v.mpc);
	    break;
	case t_int16:		case t_uint16:
	    (*value->v.ppi16)[offset] = empc_get_i(r0.v.mpc);
	    break;
	case t_int32:		case t_uint32:
	    (*value->v.ppi32)[offset] = empc_get_i(r0.v.mpc);
	    break;
	case t_int:		case t_uint:
	    (*value->v.ppi64)[offset] = empc_get_i(r0.v.mpc);
	    break;
	case t_float32:
	    (*value->v.ppf32)[offset] = empc_get_d(r0.v.mpc);
	    break;
	case t_float:
	    (*value->v.ppf64)[offset] = empc_get_d(r0.v.mpc);
	    break;
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	case t_void:
	    evm_store_pointer_mpc((*value->v.v) + offset);
	    break;
    }
}

static void
store_vector_object(evalue_t *value, eint32_t offset)
{
    switch (value->t & ~t_vector) {
	case t_int8:		case t_uint8:
	case t_int16:		case t_uint16:
	case t_int32:		case t_uint32:
	case t_int:		case t_uint:
	case t_float32:		case t_float:
	    evm_raise(except_type_mismatch);
	default:
	    if (value->t & t_const)
		evm_raise(except_input_output_error);
	    break;
    }
    switch (r0.t) {
	case t_globalref:
	    evm_store_pointer_globalref((*value->v.v) + offset);
	    break;
	case t_stackref:
	    enew_localref((*value->v.v) + offset, r0.v.ref - ss);
	    break;
	case t_t_stackref:
	    enew_t_localref((*value->v.v) + offset, r0.v.ref - ss);
	    break;
	default:
	    (*value->v.v)[offset] = r0.v.o;
	    break;
    }
}

static void
store_vector(evalue_t *vector, eint32_t offset)
{
    switch (r0.t) {
	case t_void:
	    store_vector_void(vector, offset);
	    break;
	case t_int:
	    store_vector_int(vector, offset);
	    break;
	case t_float:
	    store_vector_float(vector, offset);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    store_vector_mpz(vector, offset);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    store_vector_mpq(vector, offset);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    store_vector_mpr(vector, offset);
	    break;
	case t_cdd:
	    store_vector_cdd(vector, offset);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    store_vector_cqq(vector, offset);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    store_vector_mpc(vector, offset);
	    break;
	default:
	    store_vector_object(vector, offset);
	    break;
    }
}

void
evm_sv(eint32_t rank)
{
    eint32_t	 length;
    eint32_t	 offset;
    evalue_t	*vector;
    offset = sp[-1].v.i;
    for (length = rank - 1, --sp; length; --length, --sp)
	offset += sp[-1].v.i;
    vector = sp - 1;
    if (rank != vector->v.V->rank)
	evm_raise(except_type_mismatch);
#if DEBUG
    if (unlikely((euint32_t)offset >= vector->v.V->length))
	evm_raise(except_out_of_bounds);
#endif
    store_vector(vector, offset);
    --sp;
}

/*
 *   Note that svi is only generated for initializations, as it doesn't
 * check if dimensions of multidimensional arrays changed value;
 * currently no code does it, but soon there may be code doing it,
 *   Also, a change in logic is possibly going to be done, that is to
 * handle "pointer" objects as single dimensional arrays, if they
 * point to a vector.
 */
void
evm_svi(eint32_t offset)
{
    evalue_t	*vector;
    vector = sp - 1;
    if (!evector_type_p(vector->t))
	evm_raise(except_type_mismatch);
    store_vector(vector, offset);
    --sp;
}

void
evm_svref(eint32_t arg)
{
    eint32_t	 offset;
    evalue_t	*vector;
    assert(sp[-1].t == t_vectorref);
    vector = sp - 1;
    offset = vector->v.vref.offset;
    /* FIXME could have a hint in arg telling if side effects could
     * have changed vector length */
    if (unlikely((euint32_t)offset >= vector->v.V->length))
	evm_raise(except_out_of_bounds);
    vector->t = eobject_type(vector->v.o);
    store_vector(vector, offset);
    if (arg) {
	load_value(sp - 2);
	sp -= 2;
    }
    else
	--sp;
}

void
evm_sr(eint32_t base, eint32_t offset, eint32_t type)
{
    eobject_t	pointer;
    if (sp[-1].t != base)
	evm_match_inheritance(base, sp[-1].t, offset);
    pointer = sp[-1].v.r + offset;
    store_object_type(pointer, type);
    --sp;
}

void
evm_srref(eint32_t arg)
{
    assert(sp[-1].t == t_recordref);
    store_object_type(sp[-1].v.r + sp[-1].v.rref.offset, sp[-1].v.rref.type);
    if (arg) {
	load_value(sp - 2);
	sp -= 2;
    }
    else
	--sp;
}

void
evm_sc(eint32_t offset, eint32_t type)
{
    store_object_type(bp[-2].v.r + offset, type);
}

void
evm_sref(void)
{
    eint32_t	 i;
    evalue_t	*p;
    evalue_t	*v;
    v = sp - 1;
    switch (v->t) {
	case t_globalref:		case t_anonref:
	    evm_store_pointer(v->v.o);
	    break;
	case t_localref:
	    p = v->v.loc->thread->ess + v->v.loc->offset;
	    if (p >= v->v.loc->thread->esp || (p->t == t_void && p->v.o))
		evm_raise(except_invalid_argument);
	    evm_store_value(p);
	    break;
	case t_stackref:
	    evm_store_value(v->v.ref);
	    break;
	case t_t_localref:
	    p = v->v.loc->thread->ess + v->v.loc->offset;
	    if (p >= v->v.loc->thread->esp || (p->t == t_void && p->v.o))
		evm_raise(except_invalid_argument);
	    store_value_type(p, p->t);
	    break;
	case t_t_stackref:
	    p = v->v.ref;
	    store_value_type(p, p->t);
	    break;
	default:
	    if (unlikely(!(v->t & t_pointer)))
		evm_raise(except_type_mismatch);
	    v->t &= ~t_pointer;
	    i = v->v.V->offset;
	    v->v.o = v->v.V->v.u8;
	    if (v->t & t_vector)
		store_vector(v, i);
	    else
		store_object_type(v->v.r + i, v->t);
    }
    --sp;
}

eint32_t
evm_jt(void)
{
    switch (r0.t) {
	case t_void:
	    return (false);
	case t_int:
	    return (r0.v.i != 0);
	case t_float:
	    return (r0.v.d != 0);
	case t_mpr:		case t_shr:		case t_rgr:
	    return (!mpfr_zero_p(r0.v.mpr));
	default:
	    return (true);
    }
}

eint32_t
evm_jf(void)
{
    switch (r0.t) {
	case t_void:
	    return (true);
	case t_int:
	    return (r0.v.i == 0);
	case t_float:
	    return (r0.v.d == 0);
	case t_mpr:		case t_shr:		case t_rgr:
	    return (mpfr_zero_p(r0.v.mpr));
	default:
	    return (false);
    }
}

eobject_t
evm_jh(eint32_t offset)
{
    ecase_t	*c;
    ehswitch_t	*h;
    eint32_t	 n;
    eint_t	 i;
    switch (r0.t) {
	case t_void:
	    i = 0;
	    break;
	case t_int:
	    i = r0.v.i;
	    break;
	case t_float:
	    i = r0.v.d;
	    if (i != r0.v.d)
		goto fail;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    if (mpfr_integer_p(r0.v.mpr)) {
		empz_set_r(thr_zr, r0.v.mpr);
		if (!empz_fit_i(thr_zr))
		    goto fail;
	    }
	    else
		goto fail;
	    i = empz_get_i(thr_zr);
	    break;
	default:
	    goto fail;
    }
    h = els[offset];
    if (i >= h->imin && i <= h->imax) {
	if ((c = h->cases[i & h->mask])) {
	    n = eobject_length(c) / sizeof(ecase_t) - 1;
	    for (; n >= 0 && c->value != i; --n, ++c)
		;
	    if (n >= 0)
		return ((eobject_t)c->label);
	}
    }
fail:
#if JITVM
    return (null);
#else
    return ((eobject_t)1);
#endif
}

eobject_t
evm_jv(eint32_t offset)
{
    evswitch_t	*v;
    eint_t	 i;
    switch (r0.t) {
	case t_void:
	    i = 0;
	    break;
	case t_int:
	    i = r0.v.i;
	    break;
	case t_float:
	    i = r0.v.d;
	    if (i != r0.v.d)
		goto fail;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    if (mpfr_integer_p(r0.v.mpr)) {
		empz_set_r(thr_zr, r0.v.mpr);
		if (!empz_fit_i(thr_zr))
		    goto fail;
	    }
	    else
		goto fail;
	    i = empz_get_i(thr_zr);
	    break;
	default:
	    goto fail;
    }
    v = els[offset];
    if (i < v->imin || i > v->imax)
	goto fail;
    return ((eobject_t)v->cases[i & v->mask]);
fail:
#if JITVM
    return (null);
#else
    return ((eobject_t)1);
#endif
}

void
evm_stack_resize(eint32_t length)
{
    evalue_t	*p;
    p = ss;
    length = (length + 8192) & ~8191;
    eresize_object((eobject_t *)&ss, length * sizeof(evalue_t));
    thread_self->len = length;
    if (ss != p) {
	for (length = sp - p - 1; length > 0; --length) {
	    if (ss[length].t == t_void && ss[length].v.o &&
		ss[length - 1].t == t_void && ss[length - 1].v.o) {
		/* relocate saved bp */
		ss[length].v.ref = ss + (ss[length].v.ref - p);
		/* saved ip is already in place */
		--length;
	    }
	}
	sp = ss + (sp - p);
	bp = ss + (bp - p);
    }
}

void
evm_enter(eint32_t l, eint32_t e, eint32_t ac, eint32_t lc, eint32_t *t)
{
    register evalue_t	*p;
    eint32_t		 length;
    length = e + l + (sp - ss);
    if (unlikely(length >= thread_self->len))
	evm_stack_resize(length);
    if (ac) {
	for (p = bp - 2; ac; ac--, p--, t++) {
	    if (*t && p->t != *t) {
		switch (*t) {
		    case t_int8:		case t_uint8:
			switch (p->t) {
			    case t_void:
				p->v.i8 = 0;
				break;
			    case t_int8:	case t_uint8:
			    case t_int16:	case t_uint16:
			    case t_int32:	case t_uint32:
			    case t_int:		case t_uint:
				break;
			    case t_float32:
				p->v.i8 = p->v.f32;
				break;
			    case t_float:
				p->v.i8 = p->v.d;
				break;
			    case t_mpz:		case t_shz:
				p->v.i8 = empz_get_i(p->v.mpz);
				break;
			    case t_mpq:		case t_shq:
				p->v.i8 = empq_get_i(p->v.mpq);
				break;
			    case t_mpr:		case t_shr:
				p->v.i8 = empr_get_i(p->v.mpr);
				break;
			    case t_cdd:
				p->v.i8 = ecdd_get_i(p->v.cdd);
				break;
			    case t_cqq:		case t_rqq:
				p->v.i8 = ecqq_get_i(p->v.cqq);
				break;
			    case t_mpc:		case t_shc:
				p->v.i8 = empc_get_i(p->v.mpc);
				break;
			    default:
				evm_raise(except_type_mismatch);
			}
			break;
		    case t_int16:		case t_uint16:
			switch (p->t) {
			    case t_void:
				p->v.i16 = 0;
				break;
			    case t_int8:
				p->v.i16 = p->v.i8;
				break;
			    case t_uint8:
				p->v.i16 = p->v.u8;
				break;
			    case t_int16:	case t_uint16:
			    case t_int32:	case t_uint32:
			    case t_int:		case t_uint:
				break;
			    case t_float32:
				p->v.i16 = p->v.f32;
				break;
			    case t_float:
				p->v.i16 = p->v.d;
				break;
			    case t_mpz:		case t_shz:
				p->v.i16 = empz_get_i(p->v.mpz);
				break;
			    case t_mpq:		case t_shq:
				p->v.i16 = empq_get_i(p->v.mpq);
				break;
			    case t_mpr:		case t_shr:
				p->v.i16 = empr_get_i(p->v.mpr);
				break;
			    case t_cdd:
				p->v.i16 = ecdd_get_i(p->v.cdd);
				break;
			    case t_cqq:		case t_rqq:
				p->v.i16 = ecqq_get_i(p->v.cqq);
				break;
			    case t_mpc:		case t_shc:
				p->v.i16 = empc_get_i(p->v.mpc);
				break;
			    default:
				evm_raise(except_type_mismatch);
			}
			break;
		    case t_int32:		case t_uint32:
			switch (p->t) {
			    case t_void:
				p->v.i32 = 0;
				break;
			    case t_int8:
				p->v.i32 = p->v.i8;
				break;
			    case t_uint8:
				p->v.i32 = p->v.u8;
				break;
			    case t_int16:
				p->v.i32 = p->v.i16;
				break;
			    case t_uint16:
				p->v.i32 = p->v.u16;
				break;
			    case t_int32:	case t_uint32:
			    case t_int:		case t_uint:
				break;
			    case t_float32:
				p->v.i32 = p->v.f32;
				break;
			    case t_float:
				p->v.i32 = p->v.d;
				break;
			    case t_mpz:		case t_shz:
				p->v.i32 = empz_get_i(p->v.mpz);
				break;
			    case t_mpq:		case t_shq:
				p->v.i32 = empq_get_i(p->v.mpq);
				break;
			    case t_mpr:		case t_shr:
				p->v.i32 = empr_get_i(p->v.mpr);
				break;
			    case t_cdd:
				p->v.i32 = ecdd_get_i(p->v.cdd);
				break;
			    case t_cqq:		case t_rqq:
				p->v.i32 = ecqq_get_i(p->v.cqq);
				break;
			    case t_mpc:		case t_shc:
				p->v.i32 = empc_get_i(p->v.mpc);
				break;
			    default:
				evm_raise(except_type_mismatch);
			}
			break;
		    case t_int:			case t_uint:
			switch (p->t) {
			    case t_void:
				p->v.i = 0;
				break;
			    case t_int8:
				p->v.i = p->v.i8;
				break;
			    case t_uint8:
				p->v.i = p->v.u8;
				break;
			    case t_int16:
				p->v.i = p->v.i16;
				break;
			    case t_uint16:
				p->v.i = p->v.u16;
				break;
			    case t_int32:
				p->v.i = p->v.i32;
				break;
			    case t_uint32:
				p->v.i = p->v.u32;
				break;
			    case t_int:		case t_uint:
				break;
			    case t_float32:
				p->v.i = p->v.f32;
				break;
			    case t_float:
				p->v.i = p->v.d;
				break;
			    case t_mpz:		case t_shz:
				p->v.i = empz_get_i(p->v.mpz);
				break;
			    case t_mpq:		case t_shq:
				p->v.i = empq_get_i(p->v.mpq);
				break;
			    case t_mpr:		case t_shr:
				p->v.i = empr_get_i(p->v.mpr);
				break;
			    case t_cdd:
				p->v.i = ecdd_get_i(p->v.cdd);
				break;
			    case t_cqq:		case t_rqq:
				p->v.i = ecqq_get_i(p->v.cqq);
				break;
			    case t_mpc:		case t_shc:
				p->v.i = empc_get_i(p->v.mpc);
				break;
			    default:
				evm_raise(except_type_mismatch);
			}
			break;
		    case t_float32:
			switch (p->t) {
			    case t_void:
				p->v.f32 = 0.0;
				break;
			    case t_int8:
				p->v.f32 = p->v.i8;
				break;
			    case t_uint8:
				p->v.f32 = p->v.u8;
				break;
			    case t_int16:
				p->v.f32 = p->v.i16;
				break;
			    case t_uint16:
				p->v.f32 = p->v.u16;
				break;
			    case t_int32:
				p->v.f32 = p->v.i32;
				break;
			    case t_uint32:
				p->v.f32 = p->v.u32;
				break;
			    case t_int:
				p->v.f32 = p->v.i;
				break;
			    case t_uint:
				p->v.f32 = p->v.u;
				break;
			    case t_float32:
				break;
			    case t_float:
				p->v.f32 = p->v.d;
				break;
			    case t_mpz:		case t_shz:
				p->v.f32 = empz_get_d(p->v.mpz);
				break;
			    case t_mpq:		case t_shq:
				p->v.f32 = empq_get_d(p->v.mpq);
				break;
			    case t_mpr:		case t_shr:
				p->v.f32 = empr_get_d(p->v.mpr);
				break;
			    case t_cdd:
				p->v.f32 = ecdd_get_d(p->v.cdd);
				break;
			    case t_cqq:		case t_rqq:
				p->v.f32 = ecqq_get_d(p->v.cqq);
				break;
			    case t_mpc:		case t_shc:
				p->v.f32 = empc_get_d(p->v.mpc);
				break;
			    default:
				evm_raise(except_type_mismatch);
			}
			break;
		    case t_float:
			switch (p->t) {
			    case t_void:
				p->v.d = 0.0;
				break;
			    case t_int8:
				p->v.d = p->v.i8;
				break;
			    case t_uint8:
				p->v.d = p->v.u8;
				break;
			    case t_int16:
				p->v.d = p->v.i16;
				break;
			    case t_uint16:
				p->v.d = p->v.u16;
				break;
			    case t_int32:
				p->v.d = p->v.i32;
				break;
			    case t_uint32:
				p->v.d = p->v.u32;
				break;
			    case t_int:
				p->v.d = p->v.i;
				break;
			    case t_uint:
				p->v.d = p->v.u;
				break;
			    case t_float32:
				p->v.d = p->v.f32;
				break;
			    case t_float:
				break;
			    case t_mpz:		case t_shz:
				p->v.d = empz_get_d(p->v.mpz);
				break;
			    case t_mpq:		case t_shq:
				p->v.d = empq_get_d(p->v.mpq);
				break;
			    case t_mpr:		case t_shr:
				p->v.d = empr_get_d(p->v.mpr);
				break;
			    case t_cdd:
				p->v.d = ecdd_get_d(p->v.cdd);
				break;
			    case t_cqq:		case t_rqq:
				p->v.d = ecqq_get_d(p->v.cqq);
				break;
			    case t_mpc:		case t_shc:
				p->v.d = empc_get_d(p->v.mpc);
				break;
			    default:
				evm_raise(except_type_mismatch);
			}
			break;
		    default:
			break;
		}
		p->t = *t;
	    }
	}
    }
    if (lc) {
	for (l -= lc; lc; lc--, sp++, t++) {
	    switch (sp->t = *t) {
		case t_int8:			case t_uint8:
		    sp->v.i8 = 0;
		    break;
		case t_int16:			case t_uint16:
		    sp->v.i16 = 0;
		    break;
		case t_int32:			case t_uint32:
		    sp->v.i32 = 0;
		    break;
		case t_int:			case t_uint:
		    sp->v.i = 0;
		    break;
		case t_float32:
		    sp->v.f32 = 0.0;
		    break;
		case t_float:
		    sp->v.d = 0.0;
		    break;
		default:
		    break;
	    }
	}
    }
    for (; l; l--, sp++)
	sp->t = t_void;
}

void
evm_begin(eint32_t length)
{
    for (; length; length--, sp++)
	sp->t = t_void;
}

void
evm_off(eint32_t length)
{
    eint32_t	 offset;
    evalue_t	*vector;
    vector = sp - length;
    if (unlikely(!evector_type_p(vector->t) || vector->v.V->rank < length))
	evm_raise(except_type_mismatch);
    --length;
    offset = get_offset();
    if (unlikely((euint32_t)offset >= vector->v.V->dims[length].dim))
	evm_raise(except_out_of_bounds);
    ++sp;
    sp[-1].t = t_int;
    sp[-1].v.i = offset * vector->v.V->dims[length].mul;
}

void
evm_push(void)
{
    ++sp;
    evm_store_value_push(sp - 1);
}

void
evm_pusht(eint32_t type)
{
    ++sp;
    sp[-1].t = type;
    store_value_type(sp - 1, type);
}

void
evm_pushv(void)
{
    ++sp;
    evm_store_value_copy(sp - 1);
}

void
evm_pop(void)
{
    load_value(sp - 1);
    /* FIXME There is a possible race condition on post inc/dec
     * of mp objects, that saves a copy with eop_pushv and restores
     * with eop_pop. Since both, post inc/dec (that cannot be converted
     * to just pre inc/dec) and usage of eop_pop are uncommon, this
     * "workaround" should be good enough. */
    switch (r0.t) {
	case t_void:			case t_int:
	case t_float:			case t_shz:
	case t_rgz:			case t_shq:
	case t_rgq:			case t_shr:
	case t_rgr:			case t_cdd:
	case t_sqq:			case t_rqq:
	case t_shc:			case t_rgc:
	case t_globalref:
	    break;
	case t_stackref:		case t_t_stackref:
	    if (r0.v.ref >= sp) {
		r0.t = t_void;
		r0.v.o = null;
	    }
	    break;
	default:
	    obj = r0.v.o;
	    break;
    }
    --sp;
}

eobject_t
evm_call(eint32_t offset, eobject_t ip)
{
    sp += 2;
    sp[-2].t = t_void;
    sp[-2].v.o = ip;
    ip = ecs[offset];
    sp[-1].t = t_void;
    sp[-1].v.o = bp;
    bp = sp - 1;
    return (ip);
}

eobject_t
evm_meth(eint32_t offset, eint32_t type, eobject_t ip)
{
    if (unlikely(r0.t >= ets_idx ||
		 ets[r0.t].nmethod <= offset ||
		 ets[r0.t].methods[offset].type != type))
	evm_raise(except_type_mismatch);
    sp += 2;
    sp[-2].t = t_void;
    sp[-2].v.o = ip;
    ip = ets[r0.t].methods[offset].code;
    sp[-1].t = t_void;
    sp[-1].v.o = bp;
    bp = sp - 1;
    return (ip);
}

eobject_t
evm_ecm(eint32_t offset, eint32_t type, eobject_t ip)
{
    eint32_t	index;
    /* don't change r0.t */
    index = r0.t;
    if (unlikely(index >= ets_idx))
	evm_raise(except_type_mismatch);
    while (index != type) {
	if ((index = ets[index].super) == t_void)
	    evm_raise(except_type_mismatch);
    }
    sp += 2;
    sp[-2].t = t_void;
    sp[-2].v.o = ip;
    ip = ets[index].methods[offset].code;
    sp[-1].t = t_void;
    sp[-1].v.o = bp;
    bp = sp - 1;
    return (ip);
}

void
evm_blt(eint32_t offset, eint32_t count)
{
    ebs[offset](count);
    /* FIXME should call the exception handler */
    if (unlikely(thread_self->except))
	evm_raise(thread_self->except);
    sp -= count;
    switch (ret.t) {
	case t_void:
	    r0.t = t_void;
	    r0.v.o = null;
	    break;
	case t_int:
	    r0.t = t_int;
	    r0.v.i = ret.v.i;
	    break;
	case t_float:
	    r0.t = t_float;
	    r0.v.d = ret.v.d;
	    break;
	case t_mpz:
	    set_rz();
	    break;
	case t_mpq:
	    set_rq();
	    break;
	case t_mpr:
	    set_rr();
	    break;
	case t_cdd:
	    r0.t = t_cdd;
	    r0.v.cdd = ret.v.cdd;
	    break;
	case t_cqq:
	    set_rqq();
	    break;
	case t_mpc:
	    set_rrr();
	    break;
	default:
	    r0.v.o = ret.v.o;
	    r0.t = ret.t;
	    break;
    }
}

eobject_t
evm_ret(eint32_t count)
{
    evalue_t	*value;
    eobject_t	 object;
    value = bp;
    object = bp[-1].v.o;
    bp = value->v.o;
    switch (r0.t) {
	case t_void:			case t_int:
	case t_float:			case t_shz:
	case t_rgz:			case t_shq:
	case t_rgq:			case t_shr:
	case t_rgr:			case t_cdd:
	case t_sqq:			case t_rqq:
	case t_shc:			case t_rgc:
	    break;
	case t_mpz:
	    empz_set(thr_zr, r0.v.mpz);
	    set_rz();
	    break;
	case t_mpq:
	    empq_set(thr_qr, r0.v.mpq);
	    set_rq();
	    break;
	case t_mpr:
	    empr_set(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_cqq:
	    ecqq_set(thr_qq, r0.v.cqq);
	    set_rqq();
	    break;
	case t_mpc:
	    empc_set(thr_c, r0.v.mpc);
	    set_rrr();
	    break;
	case t_stackref:		case t_t_stackref:
	    if (r0.v.ref >= sp) {
		r0.t = t_void;
		r0.v.o = null;
	    }
	    break;
	    /* FIXME t_globalref is confusing, because it is a
	     * direct pointer in r0 and in stack slots, and an
	     * object that holds a direct pointer if in heap memory;
	     * should make a distinction for easier reading the code,
	     * like t_stackref and t_localref usage */
	case t_globalref:
	    break;
	default:
	    /* helgrind will cause a possible data race warning,
	     * that can be ignored; thr->obj is set again for the case
	     * where an object has only one reference, and that reference
	     * is about to die, due to esp being decreased, in code like:
	     *	    type foo() { type bar = new type; ... return bar; }
	     * when foo returns, only r0 will reference the variable,
	     * and thr->obj may have changed in '...' , otherwise, it
	     * is a noop, and helgrind warns due to gc() protecting
	     * and older value of thr->obj, that was changed concurrently,
	     * thr->obj cannot be set to a new object during gc() because
	     * it will block waiting for gc_mutex.
	     */
	    obj = r0.v.o;
	    break;
    }
    sp = value - count;
    return (object);
}

static void
coerce(eint32_t type)
{
    switch (r0.t) {
	case t_void:
	    switch (type) {
		case t_int8:		case t_uint8:
		case t_int16:		case t_uint16:
		case t_int32:		case t_uint32:
		case t_int:		case t_uint:
		    r0.t = t_int;
		    r0.v.i = 0;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = 0.0;
		    break;
	    }
	    break;
	case t_int:
	    switch (type) {
		case t_int8:
		    r0.v.i = (eint8_t)r0.v.i;
		    break;
		case t_uint8:
		    r0.v.i = (euint8_t)r0.v.i;
		    break;
		case t_int16:
		    r0.v.i = (eint16_t)r0.v.i;
		    break;
		case t_uint16:
		    r0.v.i = (euint16_t)r0.v.i;
		    break;
		case t_int32:
		    r0.v.i = (eint32_t)r0.v.i;
		    break;
		case t_uint32:
		    r0.v.i = (euint32_t)r0.v.i;
		    break;
		case t_int:
		    break;
		case t_uint:
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.t = t_float;
		    r0.v.f32 = r0.v.i;
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = r0.v.i;
		    break;
	    }
	    break;
	case t_float:
	    switch (type) {
		case t_int8:
		    r0.t = t_int;
		    r0.v.i = (eint8_t)r0.v.d;
		    break;
		case t_uint8:
		    r0.t = t_int;
		    r0.v.i = (euint8_t)r0.v.d;
		    break;
		case t_int16:
		    r0.t = t_int;
		    r0.v.i = (eint16_t)r0.v.d;
		    break;
		case t_uint16:
		    r0.t = t_int;
		    r0.v.i = (euint16_t)r0.v.d;
		    break;
		case t_int32:
		    r0.t = t_int;
		    r0.v.i = (eint32_t)r0.v.d;
		    break;
		case t_uint32:
		    r0.t = t_int;
		    /* FIXME aparent gcc (4.4.3?) weirdness in rounding of
		     * some values, but "corrected" at least for the test
		     * current cases with this... problems apparently only
		     * with integers with only the topmost bit set
		     * (lack of -fwrapv ? that apparently doesn't prevent
		     *  it changing int->float32->float64 to int->float64,
		     *  what still needs to check/correct here...)
		     */
		    r0.v.i32 = r0.v.d;
		    r0.v.i = r0.v.u32;
		    break;
		case t_int:
		    r0.t = t_int;
		    r0.v.i = r0.v.d;
		    break;
		case t_uint:
		    r0.t = t_int;
		    r0.v.i = r0.v.d;
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.v.f32 = r0.v.d;
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    break;
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    switch (type) {
		case t_int8:
		    r0.t = t_int;
		    r0.v.i = (eint8_t)empz_get_i(r0.v.mpz);
		    break;
		case t_uint8:
		    r0.t = t_int;
		    r0.v.i = (euint8_t)empz_get_i(r0.v.mpz);
		    break;
		case t_int16:
		    r0.t = t_int;
		    r0.v.i = (eint16_t)empz_get_i(r0.v.mpz);
		    break;
		case t_uint16:
		    r0.t = t_int;
		    r0.v.i = (euint16_t)empz_get_i(r0.v.mpz);
		    break;
		case t_int32:
		    r0.t = t_int;
		    r0.v.i = (eint32_t)empz_get_i(r0.v.mpz);
		    break;
		case t_uint32:
		    r0.t = t_int;
		    r0.v.i = (euint32_t)empz_get_i(r0.v.mpz);
		    break;
		case t_int:
		    r0.t = t_int;
		    r0.v.i = empz_get_i(r0.v.mpz);
		    break;
		case t_uint:
		    r0.t = t_int;
		    r0.v.i = empz_get_i(r0.v.mpz);
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.t = t_float;
		    r0.v.f32 = empz_get_d(r0.v.mpz);
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = empz_get_d(r0.v.mpz);
		    break;
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    switch (type) {
		case t_int8:
		    r0.t = t_int;
		    r0.v.i = (eint8_t)empq_get_i(r0.v.mpq);
		    break;
		case t_uint8:
		    r0.t = t_int;
		    r0.v.i = (euint8_t)empq_get_i(r0.v.mpq);
		    break;
		case t_int16:
		    r0.t = t_int;
		    r0.v.i = (eint16_t)empq_get_i(r0.v.mpq);
		    break;
		case t_uint16:
		    r0.t = t_int;
		    r0.v.i = (euint16_t)empq_get_i(r0.v.mpq);
		    break;
		case t_int32:
		    r0.t = t_int;
		    r0.v.i = (eint32_t)empq_get_i(r0.v.mpq);
		    break;
		case t_uint32:
		    r0.t = t_int;
		    r0.v.i = (euint32_t)empq_get_i(r0.v.mpq);
		    break;
		case t_int:
		    r0.t = t_int;
		    r0.v.i = empq_get_i(r0.v.mpq);
		    break;
		case t_uint:
		    r0.t = t_int;
		    r0.v.i = empq_get_i(r0.v.mpq);
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.t = t_float;
		    r0.v.f32 = empq_get_d(r0.v.mpq);
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = empq_get_d(r0.v.mpq);
		    break;
	    }
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    switch (type) {
		case t_int8:
		    r0.t = t_int;
		    r0.v.i = (eint8_t)empr_get_i(r0.v.mpr);
		    break;
		case t_uint8:
		    r0.t = t_int;
		    r0.v.i = (euint8_t)empr_get_i(r0.v.mpr);
		    break;
		case t_int16:
		    r0.t = t_int;
		    r0.v.i = (eint16_t)empr_get_i(r0.v.mpr);
		    break;
		case t_uint16:
		    r0.t = t_int;
		    r0.v.i = (euint16_t)empr_get_i(r0.v.mpr);
		    break;
		case t_int32:
		    r0.t = t_int;
		    r0.v.i = (eint32_t)empr_get_i(r0.v.mpr);
		    break;
		case t_uint32:
		    r0.t = t_int;
		    r0.v.i = (euint32_t)empr_get_i(r0.v.mpr);
		    break;
		case t_int:
		    r0.t = t_int;
		    r0.v.i = empr_get_i(r0.v.mpr);
		    break;
		case t_uint:
		    r0.t = t_int;
		    r0.v.i = empr_get_i(r0.v.mpr);
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.t = t_float;
		    r0.v.f32 = empr_get_d(r0.v.mpr);
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = empr_get_d(r0.v.mpr);
		    break;
	    }
	    break;
	case t_cdd:
	    switch (type) {
		case t_int8:
		    r0.t = t_int;
		    r0.v.i = (eint8_t)ecdd_get_i(r0.v.cdd);
		    break;
		case t_uint8:
		    r0.t = t_int;
		    r0.v.i = (euint8_t)ecdd_get_i(r0.v.cdd);
		    break;
		case t_int16:
		    r0.t = t_int;
		    r0.v.i = (eint16_t)ecdd_get_i(r0.v.cdd);
		    break;
		case t_uint16:
		    r0.t = t_int;
		    r0.v.i = (euint16_t)ecdd_get_i(r0.v.cdd);
		    break;
		case t_int32:
		    r0.t = t_int;
		    r0.v.i = (eint32_t)ecdd_get_i(r0.v.cdd);
		    break;
		case t_uint32:
		    r0.t = t_int;
		    r0.v.i = (euint32_t)ecdd_get_i(r0.v.cdd);
		    break;
		case t_int:
		    r0.t = t_int;
		    r0.v.i = ecdd_get_i(r0.v.cdd);
		    break;
		case t_uint:
		    r0.t = t_int;
		    r0.v.i = ecdd_get_i(r0.v.cdd);
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.t = t_float;
		    r0.v.f32 = ecdd_get_d(r0.v.cdd);
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = ecdd_get_d(r0.v.cdd);
		    break;
	    }
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    switch (type) {
		case t_int8:
		    r0.t = t_int;
		    r0.v.i = (eint8_t)ecqq_get_i(r0.v.cqq);
		    break;
		case t_uint8:
		    r0.t = t_int;
		    r0.v.i = (euint8_t)ecqq_get_i(r0.v.cqq);
		    break;
		case t_int16:
		    r0.t = t_int;
		    r0.v.i = (eint16_t)ecqq_get_i(r0.v.cqq);
		    break;
		case t_uint16:
		    r0.t = t_int;
		    r0.v.i = (euint16_t)ecqq_get_i(r0.v.cqq);
		    break;
		case t_int32:
		    r0.t = t_int;
		    r0.v.i = (eint32_t)ecqq_get_i(r0.v.cqq);
		    break;
		case t_uint32:
		    r0.t = t_int;
		    r0.v.i = (euint32_t)ecqq_get_i(r0.v.cqq);
		    break;
		case t_int:
		    r0.t = t_int;
		    r0.v.i = ecqq_get_i(r0.v.cqq);
		    break;
		case t_uint:
		    r0.t = t_int;
		    r0.v.i = ecqq_get_i(r0.v.cqq);
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.t = t_float;
		    r0.v.f32 = ecqq_get_d(r0.v.cqq);
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = ecqq_get_d(r0.v.cqq);
		    break;
	    }
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    switch (type) {
		case t_int8:
		    r0.t = t_int;
		    r0.v.i = (eint8_t)empc_get_i(r0.v.mpc);
		    break;
		case t_uint8:
		    r0.t = t_int;
		    r0.v.i = (euint8_t)empc_get_i(r0.v.mpc);
		    break;
		case t_int16:
		    r0.t = t_int;
		    r0.v.i = (eint16_t)empc_get_i(r0.v.mpc);
		    break;
		case t_uint16:
		    r0.t = t_int;
		    r0.v.i = (euint16_t)empc_get_i(r0.v.mpc);
		    break;
		case t_int32:
		    r0.t = t_int;
		    r0.v.i = (eint32_t)empc_get_i(r0.v.mpc);
		    break;
		case t_uint32:
		    r0.t = t_int;
		    r0.v.i = (euint32_t)empc_get_i(r0.v.mpc);
		    break;
		case t_int:
		    r0.t = t_int;
		    r0.v.i = empc_get_i(r0.v.mpc);
		    break;
		case t_uint:
		    r0.t = t_int;
		    r0.v.i = empc_get_i(r0.v.mpc);
		    if (unlikely(r0.v.i < 0)) {
			empz_set_u(thr_zr, r0.v.i);
			set_rz();
		    }
		    break;
		case t_float32:
		    r0.t = t_float;
		    r0.v.f32 = empc_get_d(r0.v.mpc);
		    /* FIXME barrier to ensure conversion */
		    r0.v.d = r0.v.f32;
		    break;
		default:
		    r0.t = t_float;
		    r0.v.d = empc_get_d(r0.v.mpc);
		    break;
	    }
	    break;
	default:
	    evm_raise(except_type_mismatch);
    }
}

eobject_t
evm_rett(eint32_t count, eint32_t type)
{
    evalue_t	*value;
    eobject_t	 object;
    value = bp;
    object = bp[-1].v.o;
    bp = value->v.o;
    coerce(type);
    sp = value - count;
    return (object);
}

void
evm_ne(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_ne(v);
	    break;
	case t_int:
	    evm_i_ne(v);
	    break;
	case t_float:
	    evm_d_ne(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_ne(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_ne(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_ne(v);
	    break;
	case t_cdd:
	    evm_dd_ne(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_ne(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_ne(v);
	    break;
	default:
	    evm_a_ne(v);
	    break;
    }
    sp = v;
}

void
evm_lt(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_lt(v);
	    break;
	case t_int:
	    evm_i_lt(v);
	    break;
	case t_float:
	    evm_d_lt(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_lt(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_lt(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_lt(v);
	    break;
	default:
	    evm_raise(except_not_a_real_number);
    }
    sp = v;
}

void
evm_le(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_le(v);
	    break;
	case t_int:
	    evm_i_le(v);
	    break;
	case t_float:
	    evm_d_le(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_le(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_le(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_le(v);
	    break;
	default:
	    evm_raise(except_not_a_real_number);
    }
    sp = v;
}

void
evm_eq(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_eq(v);
	    break;
	case t_int:
	    evm_i_eq(v);
	    break;
	case t_float:
	    evm_d_eq(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_eq(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_eq(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_eq(v);
	    break;
	case t_cdd:
	    evm_dd_eq(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_eq(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_eq(v);
	    break;
	default:
	    evm_a_eq(v);
	    break;
    }
    sp = v;
}

void
evm_ge(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_ge(v);
	    break;
	case t_int:
	    evm_i_ge(v);
	    break;
	case t_float:
	    evm_d_ge(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_ge(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_ge(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_ge(v);
	    break;
	default:
	    evm_raise(except_not_a_real_number);
    }
    sp = v;
}

void
evm_gt(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_gt(v);
	    break;
	case t_int:
	    evm_i_gt(v);
	    break;
	case t_float:
	    evm_d_gt(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_gt(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_gt(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_gt(v);
	    break;
	default:
	    evm_raise(except_not_a_real_number);
    }
    sp = v;
}

void
evm_and(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_and(v);
	    break;
	case t_int:
	    evm_i_and(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_and(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_and(v);
	    else
		evm_raise(except_not_an_integer);
	    break;
    }
    sp = v;
}

void
evm_or(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_or(v);
	    break;
	case t_int:
	    evm_i_or(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_or(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_or(v);
	    else
		evm_raise(except_not_an_integer);
	    break;
    }
    sp = v;
}

void
evm_xor(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_xor(v);
	    break;
	case t_int:
	    evm_i_xor(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_xor(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_xor(v);
	    else
		evm_raise(except_not_an_integer);
	    break;
    }
    sp = v;
}

static void
shift_raise(eint32_t real)
{
    switch (sp[-1].t) {
	case t_void:		case t_int:		case t_float:
	case t_mpz:		case t_shz:		case t_mpq:
	case t_shq:		case t_mpr:		case t_shr:
	    if (real)
		evm_raise(except_not_a_32_bits_integer);
	case t_cdd:		case t_cqq:		case t_sqq:
	case t_mpc:		case t_shc:
	    evm_raise(real ?
		      except_not_a_real_number : except_not_a_32_bits_integer);
	default:
	    if (!evector_type_p(sp[-1].t))
		evm_raise(real ?
			  except_not_a_real_number : except_not_a_number);
	    switch (r0.t) {
		case t_cdd:	case t_cqq:		case t_sqq:
		case t_rgq:	case t_mpc:		case t_shc:
		case t_rgc:
		    evm_raise(except_not_a_real_number);
		default:
		    evm_raise(except_not_a_32_bits_integer);
	    }
	    break;
    }
    switch (r0.t) {
	case t_float:		case t_mpq:		case t_shq:
	case t_rgq:		case t_mpr:		case t_shr:
	case t_rgr:		case t_cdd:		case t_cqq:
	case t_sqq:		case t_rqq:		case t_mpc:
	case t_shc:		case t_rgc:
	    evm_raise(except_not_a_32_bits_integer);
	default:
	    evm_raise(except_not_a_real_number);
    }
}

static eint32_t
get_shift(eint32_t real)
{
    eint32_t	shift;
    switch (r0.t) {
	case t_void:
	    shift = 0;
	    break;
	case t_int:
	    shift = r0.v.i;
	    if (shift != r0.v.i || shift == MININT32)
		shift_raise(real);
	    break;
	case t_float:
	    shift = r0.v.d;
	    if (shift != r0.v.d || shift == MININT32)
		shift_raise(real);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    if (!mpfr_integer_p(r0.v.mpr) ||
		!mpfr_fits_sint_p(r0.v.mpr, GMP_RNDZ))
		shift_raise(real);
	    shift = empr_get_i(r0.v.mpr);
	    if (unlikely(shift == MININT32))
		shift_raise(real);
	    break;
	default:
	    shift_raise(real);
    }
    return (shift);
}

void
evm_mul2(void)
{
    evalue_t	*value;
    value = sp - 1;
    if (evector_type_p(r0.t))
	evm_a_mul2(value);
    else
	evm_i_mul2(value, get_shift(0));
    sp = value;
}

void
evm_div2(void)
{
    evalue_t	*value;
    value = sp - 1;
    if (evector_type_p(r0.t))
	evm_a_div2(value);
    else
	evm_i_div2(value, get_shift(0));
    sp = value;
}

void
evm_shl(void)
{
    evalue_t	*value;
    value = sp - 1;
    if (evector_type_p(r0.t))
	evm_a_shl(value);
    else
	evm_i_shl(value, get_shift(1));
    sp = value;
}

void
evm_shr(void)
{
    evalue_t	*value;
    value = sp - 1;
    if (evector_type_p(r0.t))
	evm_a_shr(value);
    else
	evm_i_shr(value, get_shift(1));
    sp = value;
}

void
evm_add(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_add(v);
	    break;
	case t_int:
	    evm_i_add(v);
	    break;
	case t_float:
	    evm_d_add(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_add(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_add(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_add(v);
	    break;
	case t_cdd:
	    evm_dd_add(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_add(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_add(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_add(v);
	    else
		evm_raise(except_not_a_number);
	    break;
    }
    sp = v;
}

void
evm_sub(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_sub(v);
	    break;
	case t_int:
	    evm_i_sub(v);
	    break;
	case t_float:
	    evm_d_sub(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_sub(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_sub(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_sub(v);
	    break;
	case t_cdd:
	    evm_dd_sub(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_sub(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_sub(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_sub(v);
	    else
		evm_raise(except_not_a_number);
	    break;
    }
    sp = v;
}

void
evm_mul(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_mul(v);
	    break;
	case t_int:
	    evm_i_mul(v);
	    break;
	case t_float:
	    evm_d_mul(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_mul(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_mul(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_mul(v);
	    break;
	case t_cdd:
	    evm_dd_mul(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_mul(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_mul(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_mul(v);
	    else
		evm_raise(except_not_a_number);
	    break;
    }
    sp = v;
}

void
evm_div(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_div(v);
	    break;
	case t_int:
	    evm_i_div(v);
	    break;
	case t_float:
	    evm_d_div(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_div(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_div(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_div(v);
	    break;
	case t_cdd:
	    evm_dd_div(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_div(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_div(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_div(v);
	    else
		evm_raise(except_not_a_number);
	    break;
    }
    sp = v;
}

void
evm_trunc2(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_trunc2(v);
	    break;
	case t_int:
	    evm_i_trunc2(v);
	    break;
	case t_float:
	    evm_d_trunc2(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_trunc2(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_trunc2(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_trunc2(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_trunc2(v);
	    else
		evm_raise(except_not_a_real_number);
	    break;
    }
    sp = v;
}

void
evm_rem(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_rem(v);
	    break;
	case t_int:
	    evm_i_rem(v);
	    break;
	case t_float:
	    evm_d_rem(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_rem(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_rem(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_rem(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_rem(v);
	    else
		evm_raise(except_not_a_real_number);
	    break;
    }
    sp = v;
}

void
evm_atan2(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_atan2(v);
	    break;
	case t_int:
	    evm_i_atan2(v);
	    break;
	case t_float:
	    evm_d_atan2(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_atan2(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_atan2(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_atan2(v);
	    break;
	case t_cdd:
	    evm_dd_atan2(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_atan2(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_atan2(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_atan2(v);
	    else
		evm_raise(except_not_a_number);
	    break;
    }
    sp = v;
}

void
evm_pow(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_pow(v);
	    break;
	case t_int:
	    evm_i_pow(v);
	    break;
	case t_float:
	    evm_d_pow(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_pow(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_pow(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_pow(v);
	    break;
	case t_cdd:
	    evm_dd_pow(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_pow(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_pow(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_pow(v);
	    else
		evm_raise(except_not_a_number);
	    break;
    }
    sp = v;
}

void
evm_hypot(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_hypot(v);
	    break;
	case t_int:
	    evm_i_hypot(v);
	    break;
	case t_float:
	    evm_d_hypot(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_hypot(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_hypot(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_hypot(v);
	    break;
	case t_cdd:
	    evm_dd_hypot(v);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    evm_qq_hypot(v);
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_rr_hypot(v);
	    break;
	default:
	    if (evector_type_p(r0.t))
		evm_a_hypot(v);
	    else
		evm_raise(except_not_a_number);
	    break;
    }
    sp = v;
}

void
evm_complex(void)
{
    evalue_t	*v;
    v = sp - 1;
    switch (r0.t) {
	case t_void:
	    evm_v_complex(v);
	    break;
	case t_int:
	    evm_i_complex(v);
	    break;
	case t_float:
	    evm_d_complex(v);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    evm_z_complex(v);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    evm_q_complex(v);
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    evm_r_complex(v);
	    break;
	default:
	    evm_raise(except_not_a_real_number);
	    break;
    }
    sp = v;
}

void
evm_inc(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 1;
	    break;
	case t_int:
	    if (likely(r0.v.i < 0x7fffffffffffffffLL))
		++r0.v.i;
	    else {
		empz_set_i(thr_zr, r0.v.i);
		mpz_add_ui(thr_zr, thr_zr, 1);
		set_rz();
	    }
	    break;
	case t_float:
	    r0.v.d += 1;
	    break;
	case t_mpz:		case t_shz:
	    mpz_add_ui(thr_zr, r0.v.mpz, 1);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_rgz:
	    mpz_add_ui(thr_zr, thr_zr, 1);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    break;
	case t_mpq:		case t_shq:
	    mpz_add(thr_zr, mpq_numref(r0.v.mpq), mpq_denref(r0.v.mpq));
	    mpz_set(mpq_denref(thr_qr), mpq_denref(r0.v.mpq));
	    set_rq();
	    break;
	case t_rgq:
	    mpz_add(thr_zr, thr_zr, mpq_denref(thr_qr));
	    break;
	case t_mpr:		case t_shr:
	    mpfr_add_ui(thr_rr, r0.v.mpr, 1, thr_rnd);
	    set_rr();
	    break;
	case t_rgr:
	    mpfr_add_ui(thr_rr, thr_rr, 1, thr_rnd);
	    break;
	case t_cdd:
	    r0.v.cdd += 1;
	    break;
	case t_cqq:		case t_sqq:
	    mpz_add(thr_zr, mpq_numref(cqq_realref(r0.v.cqq)),
		    mpq_denref(cqq_realref(r0.v.cqq)));
	    mpz_set(mpq_denref(thr_qr), mpq_denref(cqq_realref(r0.v.cqq)));
	    mpq_set(thr_qi, cqq_imagref(r0.v.cqq));
	    set_rqq();
	    break;
	case t_rqq:
	    mpz_add(thr_zr, thr_zr, mpq_denref(thr_qr));
	    break;
	case t_mpc:		case t_shc:
	    mpfr_add_ui(thr_rr, mpc_realref(r0.v.mpc), 1, thr_rnd);
	    mpfr_set(thr_ri, mpc_imagref(r0.v.mpc), thr_rnd);
	    set_rrr();
	    break;
	case t_rgc:
	    mpfr_add_ui(thr_rr, thr_rr, 1, thr_rnd);
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_add_int(r0.v.o, 1, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_dec(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = -1;
	    break;
	case t_int:
	    if (likely(r0.v.i > -0x7fffffffffffffffLL))
		--r0.v.i;
	    else {
		empz_set_i(thr_zr, r0.v.i);
		mpz_sub_ui(thr_zr, thr_zr, 1);
		set_rz();
	    }
	    break;
	case t_float:
	    r0.v.d -= 1;
	    break;
	case t_mpz:		case t_shz:
	    mpz_sub_ui(thr_zr, r0.v.mpz, 1);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_rgz:
	    mpz_sub_ui(thr_zr, thr_zr, 1);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    break;
	case t_mpq:		case t_shq:
	    mpz_sub(thr_zr, mpq_numref(r0.v.mpq), mpq_denref(r0.v.mpq));
	    mpz_set(mpq_denref(thr_qr), mpq_denref(r0.v.mpq));
	    set_rq();
	    break;
	case t_rgq:
	    mpz_sub(thr_zr, thr_zr, mpq_denref(thr_qr));
	    break;
	case t_mpr:		case t_shr:
	    mpfr_sub_ui(thr_rr, r0.v.mpr, 1, thr_rnd);
	    set_rr();
	    break;
	case t_rgr:
	    mpfr_sub_ui(thr_rr, thr_rr, 1, thr_rnd);
	    break;
	case t_cdd:
	    r0.v.cdd -= 1;
	    break;
	case t_cqq:		case t_sqq:
	    mpz_sub(thr_zr, mpq_numref(cqq_realref(r0.v.cqq)),
		    mpq_denref(cqq_realref(r0.v.cqq)));
	    mpz_set(mpq_denref(thr_qr), mpq_denref(cqq_realref(r0.v.cqq)));
	    mpq_set(thr_qi, cqq_imagref(r0.v.cqq));
	    set_rqq();
	    break;
	case t_rqq:
	    mpz_sub(thr_zr, thr_zr, mpq_denref(thr_qr));
	    break;
	case t_mpc:		case t_shc:
	    mpfr_sub_ui(thr_rr, mpc_realref(r0.v.mpc), 1, thr_rnd);
	    mpfr_set(thr_ri, mpc_imagref(r0.v.mpc), thr_rnd);
	    set_rrr();
	    break;
	case t_rgc:
	    mpfr_sub_ui(thr_rr, thr_rr, 1, thr_rnd);
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_sub_int(r0.v.o, 1, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_bool(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	    r0.v.i = !!r0.v.i;
	    break;
	case t_float:
	    r0.t = t_int;
	    r0.v.i = !!r0.v.d;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	    r0.v.i = !mpfr_zero_p(r0.v.mpr);
	    break;
	default:
	    r0.t = t_int;
	    r0.v.i = 1;
	    break;
    }
}

void
evm_not(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 1;
	    break;
	case t_int:
	    r0.v.i = !r0.v.i;
	    break;
	case t_float:
	    r0.t = t_int;
	    r0.v.i = !r0.v.d;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	    r0.v.i = mpfr_zero_p(r0.v.mpr);
	    break;
	default:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
    }
}

void
evm_com(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = -1;
	    break;
	case t_int:
	    r0.v.i = ~r0.v.i;
	    break;
	case t_float:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_mpr:		case t_shr:		case t_rgr:
	case t_cdd:
	case t_cqq:		case t_sqq:		case t_rqq:
	case t_mpc:		case t_shc:		case t_rgc:
	    evm_raise(except_not_an_integer);
	case t_mpz:		case t_shz:
	    if (ez_com(thr_zr, r0.v.mpz)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_rgz:
	    if (ez_com(thr_zr, thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_an_integer);
	    evector_com(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_inv(void)
{
    switch (r0.t) {
	case t_void:
	    evm_raise(except_floating_point_error);
	case t_int:
	    if (likely(r0.v.i != 1 && r0.v.i != -1)) {
		/* bypass mpq_inv(), that should generate a signal */
		if (unlikely(r0.v.i == 0))
		    evm_raise(except_floating_point_error);
		mpz_set_ui(thr_zr, 1);
		empz_set_i(mpq_denref(thr_qr), r0.v.i);
		mpq_canonicalize(thr_qr);
		set_rq();
	    }
	    break;
	case t_float:
	    r0.v.d = 1 / r0.v.d;
	    break;
	case t_mpz:		case t_shz:
	    if (mpz_sgn(r0.v.mpz) < 0) {
		mpz_neg(mpq_denref(thr_qr), r0.v.mpz);
		mpz_set_si(thr_zr, -1);
	    }
	    else {
		mpz_set(mpq_denref(thr_qr), r0.v.mpz);
		mpz_set_ui(thr_zr, 1);
	    }
	    set_rq();
	    break;
	case t_rgz:
	    if (mpz_sgn(thr_zr) < 0) {
		mpz_neg(mpq_denref(thr_qr), thr_zr);
		mpz_set_si(thr_zr, -1);
	    }
	    else {
		mpz_swap(mpq_denref(thr_qr), thr_zr);
		mpz_set_ui(thr_zr, 1);
	    }
	    set_rq();
	    break;
	case t_mpq:		case t_shq:
	    empq_inv(thr_qr, r0.v.mpq);
	    if (mpz_cmp_ui(mpq_denref(thr_qr), 1))
		set_rq();
	    else if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_rgq:
	    empq_inv(thr_qr, thr_qr);
	    if (mpz_cmp_ui(mpq_denref(thr_qr), 1) == 0) {
		if (empz_fit_i(thr_zr)) {
		    r0.t = t_int;
		    r0.v.i = empz_get_i(thr_zr);
		}
		else
		    set_rz();
	    }
	    break;
	case t_mpr:		case t_shr:
	    mpfr_ui_div(thr_rr, 1, r0.v.mpr, thr_rnd);
	    set_rr();
	    break;
	case t_rgr:
	    mpfr_ui_div(thr_rr, 1, thr_rr, thr_rnd);
	    break;
	case t_cdd:
	    r0.v.cdd = 1 / r0.v.cdd;
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    /* (1*b)/(b*b+bi*bi)		(-bi*1)/(b*b+bi*bi)	*/
	    mpq_mul(thr_q1, cqq_imagref(r0.v.cqq), cqq_imagref(r0.v.cqq));
	    /* (1*b)/(b*b+t1)			(-bi*1)/(b*b+t1)	*/
	    mpq_mul(thr_q2, cqq_realref(r0.v.cqq), cqq_realref(r0.v.cqq));
	    /* (1*b)/(t2+t1)			(-bi*1)/(t2+t1)		*/
	    mpq_add(thr_q1, thr_q2, thr_q1);
	    /* (1*b)/t1				(-bi*1)/t1		*/
	    mpq_neg(thr_qi, cqq_imagref(r0.v.cqq));
	    /* (1*b)/t1				i/t1			*/
	    empq_div(thr_qi, thr_qi, thr_q1);
	    /* (1*b)/t1				i			*/
	    empq_div(thr_qr, cqq_realref(r0.v.cqq), thr_q1);
	    /* r				i			*/
	    chk_rqq();
	    break;
	case t_mpc:		case t_shc:
	    mpc_set_ui(thr_c0, 1, thr_rndc);
	    ecc_div_cc_cc(thr_c, thr_c0, r0.v.mpc);
	    set_rrr();
	    break;
	case t_rgc:
	    mpc_set_ui(thr_c0, 1, thr_rndc);
	    ecc_div_cc_cc(thr_c, thr_c0, thr_c);
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_int_div(1, r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_neg(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	    if (likely(r0.v.i != MININT))
		r0.v.i = -r0.v.i;
	    else {
		empz_set_u(thr_zr, MININT);
		set_rz();
	    }
	    break;
	case t_float:
	    r0.v.d = -r0.v.d;
	    break;
	case t_mpz:		case t_shz:
	    mpz_neg(thr_zr, r0.v.mpz);
	    set_rz();
	    break;
	case t_rgz:
	    mpz_neg(thr_zr, thr_zr);
	    break;
	case t_mpq:		case t_shq:
	    mpq_neg(thr_qr, r0.v.mpq);
	    set_rq();
	    break;
	case t_rgq:
	    mpq_neg(thr_qr, thr_qr);
	    break;
	case t_mpr:		case t_shr:
	    mpfr_neg(thr_rr, r0.v.mpr, thr_rnd);
	    set_rr();
	    break;
	case t_rgr:
	    mpfr_neg(thr_rr, thr_rr, thr_rnd);
	    break;
	case t_cdd:
	    r0.v.cdd = -r0.v.cdd;
	    break;
	case t_cqq:		case t_sqq:
	    cqq_neg(thr_qq, r0.v.cqq);
	    set_rqq();
	    break;
	case t_rqq:
	    cqq_neg(thr_qq, thr_qq);
	    break;
	case t_mpc:		case t_shc:
	    mpc_neg(thr_c, r0.v.mpc, thr_rndc);
	    set_rrr();
	    break;
	case t_rgc:
	    mpc_neg(thr_c, thr_c, thr_rndc);
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_neg(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_signbit(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	    r0.v.i = r0.v.i < 0;
	    break;
	case t_float:
	    r0.t = t_int;
	    r0.v.i = signbit(r0.v.d) != 0;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    r0.t = t_int;
	    r0.v.i = mpz_sgn(r0.v.mpz) < 0;
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    r0.t = t_int;
	    r0.v.i = mpq_sgn(r0.v.mpq) < 0;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	    r0.v.i = mpfr_signbit(r0.v.mpr) != 0;
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_real_number);
	    evector_signbit(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_signum(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	    r0.v.i = ei_signum_i(r0.v.i);
	    break;
	case t_float:
	    r0.v.d = ed_signum_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    r0.t = t_int;
	    r0.v.i = ei_signum_z(r0.v.mpz);
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    r0.t = t_int;
	    r0.v.i = ei_signum_q(r0.v.mpq);
	    break;
	case t_mpr:		case t_shr:
	    er_signum_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_signum_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_signum_dd(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_signum_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_signum_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    ecc_signum_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_signum(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_rational(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	    break;
	case t_float:
	    if (unlikely(!finite(r0.v.d)))
		evm_raise(except_not_a_finite_real_number);
	    switch (eq_rational_d(thr_qr, r0.v.d)) {
		case -1:
		    set_rz();
		    break;
		case 0:
		    set_rq();
		    break;
		default:
		    r0.t = t_int;
		    r0.v.i = empz_get_i(thr_zr);
		    break;
	    }
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    if (unlikely(!mpfr_number_p(r0.v.mpr)))
		evm_raise(except_not_a_finite_real_number);
	    switch (eq_rational_r(thr_qr, r0.v.mpr)) {
		case -1:
		    set_rz();
		    break;
		case 0:
		    set_rq();
		    break;
		default:
		    r0.t = t_int;
		    r0.v.i = empz_get_i(thr_zr);
		    break;
	    }
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_real_number);
	    evector_rational(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_integer_p(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 1;
	    break;
	default:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
    }
}

void
evm_rational_p(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 1;
	    break;
	default:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
    }
}

void
evm_float_p(void)
{
    switch (r0.t) {
	case t_float:
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	    r0.v.i = 1;
	    break;
	default:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 0;
	    break;
    }
}

void
evm_real_p(void)
{
    switch (r0.t) {
	case t_void:
	case t_float:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 1;
	    break;
	default:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
    }
}

void
evm_complex_p(void)
{
    switch (r0.t) {
	case t_cdd:
	case t_cqq:		case t_sqq:		case t_rqq:
	case t_mpc:		case t_shc:		case t_rgc:
	    r0.t = t_int;
	    r0.v.i = 1;
	    break;
	default:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 0;
	    break;
    }
}

void
evm_number_p(void)
{
    switch (r0.t) {
	case t_void:
	case t_float:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_mpr:		case t_shr:		case t_rgr:
	case t_cdd:
	case t_cqq:		case t_sqq:		case t_rqq:
	case t_mpc:		case t_shc:		case t_rgc:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 1;
	    break;
	default:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
    }
}

void
evm_finite_p(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 1;
	    break;
	case t_float:
	    r0.t = t_int;
	    r0.v.i = finite(r0.v.d) ? 1 : 0;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	    r0.v.i = mpfr_number_p(r0.v.mpr) ? 1 : 0;
	    break;
	default:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
    }
}

void
evm_inf_p(void)
{
    switch (r0.t) {
	case t_float:
	    r0.t = t_int;
	    r0.v.i = isinf(r0.v.d) ? signbit(r0.v.d) ? -1 : 1 : 0;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	    r0.v.i = mpfr_inf_p(r0.v.mpr) ? mpfr_signbit(r0.v.mpr) ? -1 : 1 : 0;
	    break;
	default:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 0;
	    break;
    }
}

void
evm_nan_p(void)
{
    switch (r0.t) {
	case t_float:
	    r0.t = t_int;
	    r0.v.i = isnan(r0.v.d) ? 1 : 0;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    r0.t = t_int;
	    r0.v.i = mpfr_nan_p(r0.v.mpr) ? 1 : 0;
	    break;
	default:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 0;
	    break;
    }
}

void
evm_num(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	    break;
	case t_mpq:		case t_shq:
	    mpz_set(thr_zr, mpq_numref(r0.v.mpq));
	case t_rgq:
	    set_rz();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_rational_number);
	    evector_num(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_den(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 1;
	    break;
	case t_mpq:		case t_shq:
	    mpz_set(thr_zr, mpq_denref(r0.v.mpq));
	    set_rz();
	    break;
	case t_rgq:
	    mpz_swap(thr_zr, mpq_denref(thr_qr));
	    set_rz();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_rational_number);
	    evector_den(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_real(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_float:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_mpr:		case t_shr:		case t_rgr:
	    break;
	case t_cdd:
	    r0.t = t_float;
	    break;
	case t_cqq:		case t_sqq:
	    if (mpz_cmp_ui(mpq_denref(cqq_realref(r0.v.cqq)), 1)) {
		mpq_set(thr_qr, cqq_realref(r0.v.cqq));
		set_rq();
	    }
	    else if (empz_fit_i(mpq_numref(cqq_realref(r0.v.cqq)))) {
		r0.t = t_int;
		r0.v.i = empz_get_i(mpq_numref(cqq_realref(r0.v.cqq)));
	    }
	    else {
		mpz_set(thr_zr, mpq_numref(cqq_realref(r0.v.cqq)));
		set_rz();
	    }
	    break;
	case t_rqq:
	    if (mpz_cmp_ui(mpq_denref(thr_qr), 1))
		set_rq();
	    else if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_mpc:		case t_shc:
	    mpc_real(thr_rr, r0.v.mpc, thr_rnd);
	case t_rgc:
	    set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_real(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_imag(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 0;
	    break;
	case t_float:
	    r0.v.d = 0.0;
	    break;
	case t_mpr:		case t_shr:
	    set_rr();
	case t_rgr:
	    mpfr_set_ui(thr_rr, 0, thr_rnd);
	    break;
	case t_cdd:
	    r0.t = t_float;
	    real(r0.v.cdd) = imag(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:
	    if (mpz_cmp_ui(mpq_denref(cqq_imagref(r0.v.cqq)), 1)) {
		mpq_set(thr_qr, cqq_imagref(r0.v.cqq));
		set_rq();
	    }
	    else if (empz_fit_i(mpq_numref(cqq_imagref(r0.v.cqq)))) {
		r0.t = t_int;
		r0.v.i = empz_get_i(mpq_numref(cqq_imagref(r0.v.cqq)));
	    }
	    else {
		mpz_set(thr_zr, mpq_numref(cqq_imagref(r0.v.cqq)));
		set_rz();
	    }
	    break;
	case t_rqq:
	    if (mpz_cmp_ui(mpq_denref(thr_qi), 1)) {
		mpq_swap(thr_qi, thr_qr);
		set_rq();
	    }
	    else if (empz_fit_i(mpq_numref(thr_qi))) {
		r0.t = t_int;
		r0.v.i = empz_get_i(mpq_numref(thr_qi));
	    }
	    else {
		mpz_set(thr_zr, mpq_numref(thr_qi));
		set_rz();
	    }
	    break;
	case t_mpc:		case t_shc:
	    mpc_imag(thr_rr, r0.v.mpc, thr_rnd);
	    set_rr();
	    break;
	case t_rgc:
	    mpfr_swap(thr_ri, thr_rr);
	    set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_imag(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_arg(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_arg_i(r0.v.i);
	    }
	    else {
		er_arg_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_arg_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_arg_z(r0.v.mpz);
	    }
	    else {
		er_arg_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_arg_q(r0.v.mpq);
	    }
	    else {
		er_arg_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_arg_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_arg_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.t = t_float;
	    r0.v.d = carg(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_arg_qq(r0.v.cqq);
	    }
	    else {
		er_arg_qq(thr_rr, r0.v.cqq);
		set_rr();
	    }
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    mpc_arg(thr_rr, r0.v.mpc, thr_rnd);
	    set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_arg(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_conj(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_float:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_mpr:		case t_shr:		case t_rgr:
	    break;
	case t_cdd:
	    r0.v.cdd = conj(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:
	    mpq_neg(thr_qi, cqq_imagref(r0.v.cqq));
	    mpq_set(thr_qr, cqq_realref(r0.v.cqq));
	    set_rqq();
	    break;
	case t_rqq:
	    mpq_neg(thr_qi, thr_qi);
	    break;
	case t_mpc:		case t_shc:
	    mpfr_neg(thr_ri, mpc_imagref(r0.v.mpc), thr_rnd);
	    mpfr_set(thr_rr, mpc_realref(r0.v.mpc), thr_rnd);
	    set_rrr();
	    break;
	case t_rgc:
	    mpfr_neg(thr_ri, thr_ri, thr_rnd);
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_conj(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_floor(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	    break;
	case t_float:
	    r0.v.d = floor(r0.v.d);
	    if ((eint_t)r0.v.d == r0.v.d) {
		r0.t = t_int;
		r0.v.i = r0.v.d;
	    }
	    else {
		mpz_set_d(thr_zr, r0.v.d);
		if (empz_fit_i(thr_zr)) {
		    r0.t = t_int;
		    r0.v.i = empz_get_i(thr_zr);
		}
		else
		    set_rz();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    mpz_fdiv_q(thr_zr, mpq_numref(r0.v.mpq), mpq_denref(r0.v.mpq));
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    mpfr_floor(thr_rr, r0.v.mpr);
	    empz_set_r(thr_zr, thr_rr);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	default:
	    evm_raise(except_not_a_real_number);
	    break;
    }
}

void
evm_trunc(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	    break;
	case t_float:
	    r0.v.d = trunc(r0.v.d);
	    if ((eint_t)r0.v.d == r0.v.d) {
		r0.t = t_int;
		r0.v.i = r0.v.d;
	    }
	    else {
		mpz_set_d(thr_zr, r0.v.d);
		if (empz_fit_i(thr_zr)) {
		    r0.t = t_int;
		    r0.v.i = empz_get_i(thr_zr);
		}
		else
		    set_rz();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    mpz_tdiv_q(thr_zr, mpq_numref(r0.v.mpq), mpq_denref(r0.v.mpq));
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    mpfr_trunc(thr_rr, r0.v.mpr);
	    empz_set_r(thr_zr, thr_rr);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_real_number);
	    evector_trunc_int(r0.v.o, 1, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_round(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	    break;
	case t_float:
	    r0.v.d = round(r0.v.d);
	    if ((eint_t)r0.v.d == r0.v.d) {
		r0.t = t_int;
		r0.v.i = r0.v.d;
	    }
	    else {
		mpz_set_d(thr_zr, r0.v.d);
		if (empz_fit_i(thr_zr)) {
		    r0.t = t_int;
		    r0.v.i = empz_get_i(thr_zr);
		}
		else
		    set_rz();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (mpq_sgn(r0.v.mpq) > 0) {
		mpz_cdiv_qr(thr_zr, thr_z0,
			    mpq_numref(r0.v.mpq), mpq_denref(r0.v.mpq));
		mpz_mul_2exp(thr_z0, thr_z0, 1);
		if (mpz_cmpabs(thr_z0, mpq_denref(r0.v.mpq)) > 0)
		    mpz_sub_ui(thr_zr, thr_zr, 1);
	    }
	    else {
		mpz_fdiv_qr(thr_zr, thr_z0,
			    mpq_numref(r0.v.mpq), mpq_denref(r0.v.mpq));
		mpz_mul_2exp(thr_z0, thr_z0, 1);
		if (mpz_cmpabs(thr_z0, mpq_denref(r0.v.mpq)) > 0)
		    mpz_add_ui(thr_zr, thr_zr, 1);
	    }
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    mpfr_round(thr_rr, r0.v.mpr);
	    empz_set_r(thr_zr, thr_rr);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	default:
	    evm_raise(except_not_a_real_number);
	    break;
    }
}

void
evm_ceil(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	    break;
	case t_float:
	    r0.v.d = ceil(r0.v.d);
	    if ((eint_t)r0.v.d == r0.v.d) {
		r0.t = t_int;
		r0.v.i = r0.v.d;
	    }
	    else {
		mpz_set_d(thr_zr, r0.v.d);
		if (empz_fit_i(thr_zr)) {
		    r0.t = t_int;
		    r0.v.i = empz_get_i(thr_zr);
		}
		else
		    set_rz();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    mpz_cdiv_q(thr_zr, mpq_numref(r0.v.mpq), mpq_denref(r0.v.mpq));
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    mpfr_ceil(thr_rr, r0.v.mpr);
	    empz_set_r(thr_zr, thr_rr);
	    if (empz_fit_i(thr_zr)) {
		r0.t = t_int;
		r0.v.i = empz_get_i(thr_zr);
	    }
	    else
		set_rz();
	    break;
	default:
	    evm_raise(except_not_a_real_number);
	    break;
    }
}

void
evm_abs(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	    if (likely(r0.v.i != MININT)) {
		if (r0.v.i < 0)
		    r0.v.i = -r0.v.i;
	    }
	    else {
		empz_set_u(thr_zr, MININT);
		set_rz();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_abs_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:
	    ez_abs_z(thr_zr, r0.v.mpz);
	    set_rz();
	    break;
	case t_rgz:
	    ez_abs_z(thr_zr, thr_zr);
	    break;
	case t_mpq:		case t_shq:
	    eq_abs_q(thr_qr, r0.v.mpq);
	    set_rq();
	    break;
	case t_rgq:
	    eq_abs_q(thr_qr, thr_qr);
	    break;
	case t_mpr:		case t_shr:
	    er_abs_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_abs_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.t = t_float;
	    r0.v.d = ed_abs_dd(r0.v.cdd);
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_abs_qq(r0.v.cqq);
	    }
	    else {
		er_abs_qq(thr_rr, r0.v.cqq);
		set_rr();
	    }
	    break;
	case t_mpc:		case t_shc:		case t_rgc:
	    er_abs_cc(thr_rr, r0.v.mpc);
	    set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_abs(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_sqrt(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		if (r0.v.i >= 0) {
		    r0.t = t_float;
		    r0.v.d = ed_sqrt_i(r0.v.i);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_sqrt_i(r0.v.i);
		}
	    }
	    else if (r0.v.i >= 0) {
		er_sqrt_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    else {
		ecc_sqrt_i(thr_c, r0.v.i);
		set_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (likely(r0.v.d >= 0.0))
		    r0.v.d = ed_sqrt_d(r0.v.d);
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_sqrt_d(r0.v.d);
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		if (mpz_sgn(r0.v.mpz) >= 0) {
		    r0.t = t_float;
		    r0.v.d = ed_sqrt_z(r0.v.mpz);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_sqrt_z(r0.v.mpz);
		}
	    }
	    else if (mpz_sgn(r0.v.mpz) >= 0) {
		er_sqrt_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    else {
		ecc_sqrt_z(thr_c, r0.v.mpz);
		set_rrr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		if (mpq_sgn(r0.v.mpq) >= 0) {
		    r0.t = t_float;
		    r0.v.d = ed_sqrt_q(r0.v.mpq);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_sqrt_q(r0.v.mpq);
		}
	    }
	    else if (mpq_sgn(r0.v.mpq) >= 0) {
		er_sqrt_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    else {
		ecc_sqrt_q(thr_c, r0.v.mpq);
		set_rrr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if (mpfr_sgn(r0.v.mpr) >= 0) {
		    er_sqrt_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    mpc_set_fr(thr_c, r0.v.mpr, thr_rndc);
		    ecc_sqrt_cc(thr_c, thr_c);
		    set_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if (mpfr_sgn(thr_rr) >= 0)
		    er_sqrt_r(thr_rr, thr_rr);
		else {
		    mpc_set_fr(thr_c, thr_rr, thr_rndc);
		    ecc_sqrt_cc(thr_c, thr_c);
		    set_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_sqrt_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_sqrt_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_sqrt_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_sqrt_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_sqrt_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_sqrt(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_cbrt(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cbrt_i(r0.v.i);
	    }
	    else {
		er_cbrt_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_cbrt_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cbrt_z(r0.v.mpz);
	    }
	    else {
		er_cbrt_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cbrt_q(r0.v.mpq);
	    }
	    else {
		er_cbrt_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_cbrt_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_cbrt_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_cbrt_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_cbrt_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_cbrt_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_cbrt_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_cbrt_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_cbrt(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_sin(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_sin_i(r0.v.i);
	    }
	    else {
		er_sin_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_sin_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_sin_z(r0.v.mpz);
	    }
	    else {
		er_sin_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_sin_q(r0.v.mpq);
	    }
	    else {
		er_sin_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_sin_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_sin_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_sin_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_sin_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_sin_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_sin_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_sin_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_sin(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_cos(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 1.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 1, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cos_i(r0.v.i);
	    }
	    else {
		er_cos_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_cos_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cos_z(r0.v.mpz);
	    }
	    else {
		er_cos_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cos_q(r0.v.mpq);
	    }
	    else {
		er_cos_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_cos_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_cos_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_cos_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_cos_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_cos_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_cos_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_cos_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_cos(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_tan(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_tan_i(r0.v.i);
	    }
	    else {
		er_tan_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_tan_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_tan_z(r0.v.mpz);
	    }
	    else {
		er_tan_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_tan_q(r0.v.mpq);
	    }
	    else {
		er_tan_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_tan_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_tan_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_tan_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_tan_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_tan_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_tan_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_tan_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_tan(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_asin(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (r0.v.i <= 1 && r0.v.i >= -1) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_asin_i(r0.v.i);
		}
		else {
		    er_asin_i(thr_rr, r0.v.i);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_asin_i(r0.v.i);
		chk_rdd();
	    }
	    else {
		ecc_asin_i(thr_c, r0.v.i);
		set_chk_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (fabs(r0.v.d) <= 1.0)
		    r0.v.d = ed_asin_d(r0.v.d);
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_asin_d(r0.v.d);
		    chk_rdd();
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_asin_z(r0.v.mpz);
		chk_rdd();
	    }
	    else {
		ecc_asin_z(thr_c, r0.v.mpz);
		set_chk_rrr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if ((mpq_sgn(r0.v.mpq) >= 0 && mpq_cmp_ui(r0.v.mpq,  1, 1) <= 0) ||
		(mpq_sgn(r0.v.mpq) <  0 && mpq_cmp_si(r0.v.mpq, -1, 1) >= 0)) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_asin_q(r0.v.mpq);
		}
		else {
		    er_asin_q(thr_rr, r0.v.mpq);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_asin_q(r0.v.mpq);
		chk_rdd();
	    }
	    else {
		ecc_asin_q(thr_c, r0.v.mpq);
		set_chk_rrr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if ((mpfr_sgn(r0.v.mpr) >= 0 && mpfr_cmp_ui(r0.v.mpr, 1) <= 0) ||
		    (mpfr_sgn(r0.v.mpr) < 0 && mpfr_cmp_si(r0.v.mpr, -1) >= 0)) {
		    er_asin_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    ecc_asin_r(thr_c, r0.v.mpr);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if ((mpfr_sgn(thr_rr) >= 0 && mpfr_cmp_ui(thr_rr, 1) <= 0) ||
		    (mpfr_sgn(thr_rr) < 0 && mpfr_cmp_si(thr_rr, -1) >= 0))
		    er_asin_r(thr_rr, thr_rr);
		else {
		    ecc_asin_r(thr_c, thr_rr);
		    set_rr_chk_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_asin_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_asin_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_asin_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_asin_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_asin_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_asin(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_acos(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_acos_d(0.0);
	    }
	    else {
		er_acos_i(thr_rr, 0);
		set_rr();
	    }
	    break;
	case t_int:
	    if (r0.v.i <= 1 && r0.v.i >= -1) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_acos_i(r0.v.i);
		}
		else {
		    er_acos_i(thr_rr, r0.v.i);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acos_i(r0.v.i);
		chk_rdd();
	    }
	    else {
		ecc_acos_i(thr_c, r0.v.i);
		set_chk_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (fabs(r0.v.d) <= 1.0)
		    r0.v.d = ed_acos_d(r0.v.d);
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_acos_d(r0.v.d);
		    chk_rdd();
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acos_z(r0.v.mpz);
		chk_rdd();
	    }
	    else {
		ecc_acos_z(thr_c, r0.v.mpz);
		set_chk_rrr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if ((mpq_sgn(r0.v.mpq) >= 0 && mpq_cmp_ui(r0.v.mpq,  1, 1) <= 0) ||
		(mpq_sgn(r0.v.mpq) <  0 && mpq_cmp_si(r0.v.mpq, -1, 1) >= 0)) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_acos_q(r0.v.mpq);
		}
		else {
		    er_acos_q(thr_rr, r0.v.mpq);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acos_q(r0.v.mpq);
		chk_rdd();
	    }
	    else {
		ecc_acos_q(thr_c, r0.v.mpq);
		set_chk_rrr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if ((mpfr_sgn(r0.v.mpr) >= 0 && mpfr_cmp_ui(r0.v.mpr, 1) <= 0) ||
		    (mpfr_sgn(r0.v.mpr) < 0 && mpfr_cmp_si(r0.v.mpr, -1) >= 0)) {
		    er_acos_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    ecc_acos_r(thr_c, r0.v.mpr);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if ((mpfr_sgn(thr_rr) >= 0 && mpfr_cmp_ui(thr_rr, 1) <= 0) ||
		    (mpfr_sgn(thr_rr) < 0 && mpfr_cmp_si(thr_rr, -1) >= 0))
		    er_acos_r(thr_rr, thr_rr);
		else {
		    ecc_acos_r(thr_c, thr_rr);
		    set_rr_chk_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_acos_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acos_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_acos_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_acos_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_acos_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_acos(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_atan(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_atan_i(r0.v.i);
	    }
	    else {
		er_atan_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_atan_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_atan_z(r0.v.mpz);
	    }
	    else {
		er_atan_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_atan_q(r0.v.mpq);
	    }
	    else {
		er_atan_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_atan_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_atan_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_atan_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_atan_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_atan_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_atan_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_atan_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_atan(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_sinh(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_sinh_i(r0.v.i);
	    }
	    else {
		er_sinh_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_sinh_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_sinh_z(r0.v.mpz);
	    }
	    else {
		er_sinh_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_sinh_q(r0.v.mpq);
	    }
	    else {
		er_sinh_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_sinh_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_sinh_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_sinh_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_sinh_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_sinh_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_sinh_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_sinh_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_sinh(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_cosh(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 1.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 1, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cosh_i(r0.v.i);
	    }
	    else {
		er_cosh_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_cosh_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cosh_z(r0.v.mpz);
	    }
	    else {
		er_cosh_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_cosh_q(r0.v.mpq);
	    }
	    else {
		er_cosh_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_cosh_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_cosh_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_cosh_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_cosh_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_cosh_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_cosh_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_cosh_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_cosh(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_tanh(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_tanh_i(r0.v.i);
	    }
	    else {
		er_tanh_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_tanh_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_tanh_z(r0.v.mpz);
	    }
	    else {
		er_tanh_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_tanh_q(r0.v.mpq);
	    }
	    else {
		er_tanh_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_tanh_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_tanh_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_tanh_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_tanh_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_tanh_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_tanh_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_tanh_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_tanh(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_asinh(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 0.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 0, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_asinh_i(r0.v.i);
	    }
	    else {
		er_asinh_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_asinh_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_asinh_z(r0.v.mpz);
	    }
	    else {
		er_asinh_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_asinh_q(r0.v.mpq);
	    }
	    else {
		er_asinh_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_asinh_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_asinh_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_asinh_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_asinh_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_asinh_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_asinh_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_asinh_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_asinh(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_acosh(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acosh_i(0);
		chk_rdd();
	    }
	    else {
		ecc_acosh_i(thr_c, 0);
		set_chk_rrr();
	    }
	    break;
	case t_int:
	    if (r0.v.i >= 1) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_acosh_i(r0.v.i);
		}
		else {
		    er_acosh_i(thr_rr, r0.v.i);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acosh_i(r0.v.i);
		chk_rdd();
	    }
	    else {
		ecc_acosh_i(thr_c, r0.v.i);
		set_chk_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (r0.v.d >= 1.0)
		    r0.v.d = ed_acosh_d(r0.v.d);
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_acosh_d(r0.v.d);
		    chk_rdd();
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (mpz_sgn(r0.v.mpz) > 0) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_acosh_z(r0.v.mpz);
		}
		else {
		    er_acosh_z(thr_rr, r0.v.mpz);
		    set_rr();
		}
	    }
	    else {
		if (!flt) {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_acosh_z(r0.v.mpz);
		    chk_rdd();
		}
		else {
		    ecc_acosh_z(thr_c, r0.v.mpz);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (mpq_cmp_ui(r0.v.mpq, 1, 1) >= 0) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_acosh_q(r0.v.mpq);
		}
		else {
		    er_acosh_q(thr_rr, r0.v.mpq);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acosh_q(r0.v.mpq);
		chk_rdd();
	    }
	    else {
		ecc_acosh_q(thr_c, r0.v.mpq);
		set_chk_rrr();
	    }

	    break;

	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if (mpfr_cmp_ui(r0.v.mpr, 1) >= 0) {
		    er_acosh_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    ecc_acosh_r(thr_c, r0.v.mpr);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if (mpfr_cmp_ui(r0.v.mpr, 1) >= 0)
		    er_acosh_r(thr_rr, thr_rr);
		else {
		    ecc_acosh_r(thr_c, thr_rr);
		    set_rr_chk_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_acosh_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_acosh_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_acosh_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_acosh_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_acosh_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_acosh(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_atanh(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_atanh_d(0.0);
	    }
	    else {
		er_atanh_i(thr_rr, 0);
		set_rr();
	    }
	    break;
	case t_int:
	    if (r0.v.i < 1 && r0.v.i > -1) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_atanh_i(r0.v.i);
		}
		else {
		    er_atanh_i(thr_rr, r0.v.i);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_atanh_i(r0.v.i);
		chk_rdd();
	    }
	    else {
		ecc_atanh_i(thr_c, r0.v.i);
		set_chk_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (fabs(r0.v.d) < 1.0)
		    r0.v.d = ed_atanh_d(r0.v.d);
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_atanh_d(r0.v.d);
		    chk_rdd();
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_atanh_z(r0.v.mpz);
		chk_rdd();
	    }
	    else {
		ecc_atanh_z(thr_c, r0.v.mpz);
		set_chk_rrr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if ((mpq_sgn(r0.v.mpq) >= 0 && mpq_cmp_ui(r0.v.mpq,  1, 1) < 0) ||
		(mpq_sgn(r0.v.mpq) <  0 && mpq_cmp_si(r0.v.mpq, -1, 1) > 0)) {
		if (!flt) {
		    r0.t = t_float;
		    r0.v.d = ed_atanh_q(r0.v.mpq);
		}
		else {
		    er_atanh_q(thr_rr, r0.v.mpq);
		    set_rr();
		}
	    }
	    else if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_atanh_q(r0.v.mpq);
		chk_rdd();
	    }
	    else {
		ecc_atanh_q(thr_c, r0.v.mpq);
		set_chk_rrr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if ((mpfr_sgn(r0.v.mpr) >= 0 && mpfr_cmp_ui(r0.v.mpr, 1) < 0) ||
		    (mpfr_sgn(r0.v.mpr) < 0 && mpfr_cmp_si(r0.v.mpr, -1) > 0)) {
		    er_atanh_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    ecc_atanh_r(thr_c, r0.v.mpr);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if ((mpfr_sgn(thr_rr) >= 0 && mpfr_cmp_ui(thr_rr, 1) < 0) ||
		    (mpfr_sgn(thr_rr) < 0 && mpfr_cmp_si(thr_rr, -1) > 0))
		    er_atanh_r(thr_rr, thr_rr);
		else {
		    ecc_atanh_r(thr_c, thr_rr);
		    set_rr_chk_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_atanh_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_atanh_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_atanh_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_atanh_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_atanh_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_atanh(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_proj(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_cqq:		case t_sqq:		case t_rqq:
	    break;
	case t_float:
	    r0.v.d = ed_proj_d(r0.v.d);
	    break;
	case t_mpr:		case t_shr:
	    er_proj_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_proj_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_proj_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_mpc:		case t_shc:
	    ecc_proj_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_proj_cc(thr_c, thr_c);
	    if (mpfr_zero_p(thr_ri))
		set_rr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_proj(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_exp(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = 1.0;
	    }
	    else {
		mpfr_set_ui(thr_rr, 1, thr_rnd);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_exp_i(r0.v.i);
	    }
	    else {
		er_exp_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    break;
	case t_float:
	    r0.v.d = ed_exp_d(r0.v.d);
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_exp_z(r0.v.mpz);
	    }
	    else {
		er_exp_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = ed_exp_q(r0.v.mpq);
	    }
	    else {
		er_exp_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    er_exp_r(thr_rr, r0.v.mpr);
	    set_rr();
	    break;
	case t_rgr:
	    er_exp_r(thr_rr, thr_rr);
	    break;
	case t_cdd:
	    r0.v.cdd = edd_exp_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_exp_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_exp_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_exp_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_exp_cc(thr_c, r0.v.mpc);
	    set_rr_chk_rrr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_exp(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_log(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = -INFINITY;
	    }
	    else {
		mpfr_set_inf(thr_rr, -1);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		if (likely(r0.v.i >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log_i(r0.v.i);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log_i(r0.v.i);
		    chk_rdd();
		}
	    }
	    else if (likely(r0.v.i >= 0)) {
		er_log_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    else {
		ecc_log_i(thr_c, r0.v.i);
		set_chk_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (likely(r0.v.d >= 0.0))
		    r0.v.d = ed_log_d(r0.v.d);
		else {
		    imag(r0.v.cdd) = 0.0;
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log_dd(r0.v.cdd);
		    chk_rdd();
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		if (likely(mpz_sgn(r0.v.mpz) >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log_z(r0.v.mpz);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log_z(r0.v.mpz);
		    chk_rdd();
		}
	    }
	    else if (likely(mpz_sgn(r0.v.mpz) >= 0)) {
		er_log_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    else {
		ecc_log_z(thr_c, r0.v.mpz);
		set_chk_rrr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		if (likely(mpq_sgn(r0.v.mpq) >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log_q(r0.v.mpq);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log_q(r0.v.mpq);
		    chk_rdd();
		}
	    }
	    else if (likely(mpq_sgn(r0.v.mpq) >= 0)) {
		er_log_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    else {
		ecc_log_q(thr_c, r0.v.mpq);
		set_chk_rrr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if (likely(mpfr_sgn(r0.v.mpr) >= 0)) {
		    er_log_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    ecc_log_r(thr_c, r0.v.mpr);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if (likely(mpfr_sgn(thr_rr) >= 0))
		    er_log_r(thr_rr, thr_rr);
		else {
		    ecc_log_r(thr_c, thr_rr);
		    set_rr_chk_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_log_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_log_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_log_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_log_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_log_cc(thr_c, r0.v.mpc);
	    set_rr_chk_rrr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_log(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_log2(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = -INFINITY;
	    }
	    else {
		mpfr_set_inf(thr_rr, -1);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		if (likely(r0.v.i >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log2_i(r0.v.i);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log2_i(r0.v.i);
		    chk_rdd();
		}
	    }
	    else if (likely(r0.v.i >= 0)) {
		er_log2_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    else {
		ecc_log2_i(thr_c, r0.v.i);
		set_chk_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (likely(r0.v.d >= 0.0))
		    r0.v.d = ed_log2_d(r0.v.d);
		else {
		    imag(r0.v.cdd) = 0.0;
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log2_dd(r0.v.cdd);
		    chk_rdd();
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		if (likely(mpz_sgn(r0.v.mpz) >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log2_z(r0.v.mpz);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log2_z(r0.v.mpz);
		    chk_rdd();
		}
	    }
	    else if (likely(mpz_sgn(r0.v.mpz) >= 0)) {
		er_log2_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    else {
		ecc_log2_z(thr_c, r0.v.mpz);
		set_chk_rrr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		if (likely(mpq_sgn(r0.v.mpq) >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log2_q(r0.v.mpq);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log2_q(r0.v.mpq);
		    chk_rdd();
		}
	    }
	    else if (likely(mpq_sgn(r0.v.mpq) >= 0)) {
		er_log2_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    else {
		ecc_log2_q(thr_c, r0.v.mpq);
		set_chk_rrr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if (likely(mpfr_sgn(r0.v.mpr) >= 0)) {
		    er_log2_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    ecc_log2_r(thr_c, r0.v.mpr);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if (likely(mpfr_sgn(thr_rr) >= 0))
		    er_log2_r(thr_rr, thr_rr);
		else {
		    ecc_log2_r(thr_c, thr_rr);
		    set_rr_chk_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_log2_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_log2_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_log2_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_log2_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_log2_cc(thr_c, r0.v.mpc);
	    set_rr_chk_rrr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_log2(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_log10(void)
{
    switch (r0.t) {
	case t_void:
	    if (!flt) {
		r0.t = t_float;
		r0.v.d = -INFINITY;
	    }
	    else {
		mpfr_set_inf(thr_rr, -1);
		set_rr();
	    }
	    break;
	case t_int:
	    if (!flt) {
		if (likely(r0.v.i >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log10_i(r0.v.i);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log10_i(r0.v.i);
		    chk_rdd();
		}
	    }
	    else if (likely(r0.v.i >= 0)) {
		er_log10_i(thr_rr, r0.v.i);
		set_rr();
	    }
	    else {
		ecc_log10_i(thr_c, r0.v.i);
		set_chk_rrr();
	    }
	    break;
	case t_float:
	    if (likely(!isnan(r0.v.d))) {
		if (likely(r0.v.d >= 0.0))
		    r0.v.d = ed_log10_d(r0.v.d);
		else {
		    imag(r0.v.cdd) = 0.0;
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log10_dd(r0.v.cdd);
		    chk_rdd();
		}
	    }
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    if (!flt) {
		if (likely(mpz_sgn(r0.v.mpz) >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log10_z(r0.v.mpz);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log10_z(r0.v.mpz);
		    chk_rdd();
		}
	    }
	    else if (likely(mpz_sgn(r0.v.mpz) >= 0)) {
		er_log10_z(thr_rr, r0.v.mpz);
		set_rr();
	    }
	    else {
		ecc_log10_z(thr_c, r0.v.mpz);
		set_chk_rrr();
	    }
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    if (!flt) {
		if (likely(mpq_sgn(r0.v.mpq) >= 0)) {
		    r0.t = t_float;
		    r0.v.d = ed_log10_q(r0.v.mpq);
		}
		else {
		    r0.t = t_cdd;
		    r0.v.cdd = edd_log10_q(r0.v.mpq);
		    chk_rdd();
		}
	    }
	    else if (likely(mpq_sgn(r0.v.mpq) >= 0)) {
		er_log10_q(thr_rr, r0.v.mpq);
		set_rr();
	    }
	    else {
		ecc_log10_q(thr_c, r0.v.mpq);
		set_chk_rrr();
	    }
	    break;
	case t_mpr:		case t_shr:
	    if (likely(!mpfr_nan_p(r0.v.mpr))) {
		if (likely(mpfr_sgn(r0.v.mpr) >= 0)) {
		    er_log10_r(thr_rr, r0.v.mpr);
		    set_rr();
		}
		else {
		    ecc_log10_r(thr_c, r0.v.mpr);
		    set_chk_rrr();
		}
	    }
	    break;
	case t_rgr:
	    if (likely(!mpfr_nan_p(thr_rr))) {
		if (likely(mpfr_sgn(thr_rr) >= 0))
		    er_log10_r(thr_rr, thr_rr);
		else {
		    ecc_log10_r(thr_c, thr_rr);
		    set_rr_chk_rrr();
		}
	    }
	    break;
	case t_cdd:
	    r0.v.cdd = edd_log10_dd(r0.v.cdd);
	    chk_rdd();
	    break;
	case t_cqq:		case t_sqq:		case t_rqq:
	    if (!flt) {
		r0.t = t_cdd;
		r0.v.cdd = edd_log10_qq(r0.v.cqq);
		chk_rdd();
	    }
	    else {
		ecc_log10_qq(thr_c, r0.v.cqq);
		set_chk_rrr();
	    }
	    break;
	case t_mpc:		case t_shc:
	    ecc_log10_cc(thr_c, r0.v.mpc);
	    set_chk_rrr();
	    break;
	case t_rgc:
	    ecc_log10_cc(thr_c, r0.v.mpc);
	    set_rr_chk_rrr();
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
	    evector_log10(r0.v.o, r0.t & ~(t_const|t_vector));
	    r0.v.o = obj;
	    r0.t = eobject_type(obj);
	    break;
    }
}

void
evm_new(eint32_t type, eint32_t size)
{
    enew_object(&obj, type, size);
    r0.v.o = obj;
    r0.t = type;
}

void
evm_mv(eint32_t length)
{
    memcpy(sp[-1].v.o, r0.v.o, length);
    r0.v.o = sp[-1].v.o;
    r0.t = sp[-1].t;
    --sp;
}

static eint32_t
get_offset_value(evalue_t *value)
{
    eint32_t	offset;
    switch (value->t) {
	case t_void:
	    offset = 0;
	    break;
	case t_int:
	    if ((euint_t)value->v.i > most_positive_fix32)
		evm_raise(except_out_of_bounds);
	    offset = value->v.i;
	    break;
	case t_float:
	    if (value->v.d >= 0 && value->v.d <= most_positive_fix32)
		offset = r0.v.d;
	    else
		evm_raise(except_out_of_bounds);
	    break;
	case t_mpz:		case t_shz:
	    evm_raise(except_out_of_bounds);
	case t_mpq:		case t_shq:
	    mpz_set_q(thr_z0, value->v.mpq);
	    if (mpz_fits_sint_p(thr_z0))
		offset = mpz_get_si(thr_z0);
	    else
		evm_raise(except_out_of_bounds);
	    break;
	case t_mpr:		case t_shr:
	    if (mpfr_fits_sint_p(value->v.mpr, GMP_RNDZ))
		offset = empr_get_i(value->v.mpr);
	    else
		evm_raise(except_out_of_bounds);
	    break;
	default:
	    evm_raise(except_not_an_integer);
    }
    return (offset);
}

void
evm_vnew(eint32_t type, eint32_t rank)
{
    eint32_t	inner;
    eint32_t	offset;
    eint32_t	length;
    if (unlikely(r0.t != t_int || (euint_t)r0.v.i > most_positive_fix32))
	evm_raise(except_not_a_32_bits_integer);
    /* remember inner dimension */
    inner = r0.v.i;
    for (offset = rank - 1; offset; --offset) {
	length = get_offset_value(sp - offset);
	sp[-offset].t = t_int;
	sp[-offset].v.i = length;
	r0.v.i *= length;
	if (unlikely((euint_t)r0.v.i > most_positive_fix32))
	    evm_raise(except_out_of_bounds);
    }
    enew_vector((evector_t **)&obj, type, r0.v.i, rank);
    r0.v.o = obj;
    r0.t = type;
    if (--rank) {
	r0.v.V->dims[rank].dim = inner;
	r0.v.V->dims[rank].mul = 1;
	for (offset = 1; offset <= rank; offset++) {
	    r0.v.V->dims[rank - offset].dim = sp[-offset].v.i;
	    r0.v.V->dims[rank - offset].mul = 1;
	}
	for (offset = rank; offset > 0; offset--)
	    r0.v.V->dims[offset - 1].mul = r0.v.V->dims[offset].dim *
		r0.v.V->dims[offset].mul;
	sp -= rank;
    }
}

void
evm_vnewi(eint32_t type, eint32_t length, eint32_t rank, eint32_t *dims)
{
    enew_vector((evector_t **)&obj, type, length, rank);
    r0.v.o = obj;
    r0.t = type;
    if (--rank) {
	eint32_t	offset;
	for (offset = 0; offset <= rank; offset++) {
	    r0.v.V->dims[offset].dim = *dims++;
	    r0.v.V->dims[offset].mul = 1;
	}
	for (offset = rank; offset > 0; offset--)
	    r0.v.V->dims[offset - 1].mul = r0.v.V->dims[offset].dim *
		r0.v.V->dims[offset].mul;
    }
}

void
evm_vmv(eint32_t length)
{
    switch (sp[-1].t & ~(t_const|t_vector)) {
	case t_int8:			case t_uint8:
	    break;
	case t_int16:			case t_uint16:
	    length <<= 1;
	    break;
	case t_int32:			case t_uint32:
	case t_float32:
#if __WORDSIZE == 32
	default:
#endif
	    length <<= 2;
	    break;
	case t_int:			case t_uint:
	case t_float:
#if __WORDSIZE == 64
	default:
#endif
	    length <<= 3;
	    break;
    }
    memcpy(*sp[-1].v.v, *r0.v.v, length);
    r0.v.o = sp[-1].v.o;
    r0.t = sp[-1].t;
    --sp;
}

void
evm_renew(void)
{
    eint32_t	length;
    length = get_offset();
    if (unlikely((euint32_t)length > most_positive_fix32))
	evm_raise(except_out_of_bounds);
    r0.v.o = sp[-1].v.o;
    r0.t = sp[-1].t;
    if (unlikely(!evector_type_p(r0.t)) || (r0.t & t_const))
	evm_raise(except_invalid_argument);
    erenew_vector(r0.v.o, length);
}

void
evm_renewi(eint32_t length)
{
    if (unlikely(!evector_type_p(r0.t) || (r0.t & t_const)))
	evm_raise(except_invalid_argument);
    erenew_vector(r0.v.o, length);
}

/* FIXME should not need to allocate any memory, but instead, have
 * ebs[] and ecs[] objects already in the proper format */
void
evm_fref(eint32_t offset, eint32_t count, eint32_t bits)
{
    enew_lambda(&obj, bits & L_builtin ?
		ebs[offset]  : ecs[offset], count, bits);
    r0.v.o = obj;
    r0.t = t_lambda;
}

eobject_t
evm_apply(eint32_t length, eobject_t ip)
{
    eobject_t	fixnum;
    if (unlikely(r0.t != t_lambda ||
		 length < r0.v.y->args ||
		 (!(r0.v.y->bits & L_varargs) && length > r0.v.y->args)))
	evm_raise(except_invalid_argument);
    v_check(2);
    fixnum = efixnum(thread_self->vcount);
    v_push(fixnum);
    if (r0.v.y->bits & L_builtin) {
	r0.v.y->code.builtin(length);
	/* FIXME should call the exception handler from the builtin */
	if (unlikely(thread_self->except))
	    evm_raise(thread_self->except);
	switch (ret.t) {
	    case t_void:
		break;
	    case t_int:
		r0.t = t_int;
		r0.v.i = ret.v.i;
		break;
	    case t_float:
		r0.t = t_float;
		r0.v.d = ret.v.d;
		break;
	    case t_cdd:
		r0.t = t_cdd;
		r0.v.cdd = ret.v.cdd;
		break;
	    case t_mpz:
		set_rz();
		break;
	    case t_mpq:
		set_rq();
		break;
	    case t_mpr:
		set_rr();
		break;
	    case t_cqq:
		set_rqq();
		break;
	    case t_mpc:
		set_rrr();
		break;
	    default:
		r0.v.o = ret.v.o;
		r0.t = ret.t;
		break;
	}
	thread_self->vcount = length;
    }
    else {
	sp += 2;
	sp[-2].t = t_void;
	sp[-2].v.o = ip;
	sp[-1].t = t_void;
	sp[-1].v.o = bp;
	bp = sp - 1;
	ip = r0.v.y->code.lambda;
	thread_self->vcount = length - r0.v.y->args;
    }
    fixnum = efixnum(thread_self->vcount);
    v_push(fixnum);
    return (ip);
}

void
evm_aret(void)
{
    eobject_t	fixnum;
    fixnum = v_pop();
    sp -= eget_fixnum(fixnum);
    fixnum = v_pop();
    thread_self->vcount = eget_fixnum(fixnum);
}

void
evm_szof(void)
{
    if (evector_type_p(r0.t)) {
	r0.t = t_int;
	r0.v.i = r0.v.V->length;
    }
    else {
	r0.t = t_int;
	r0.v.i = 0;
    }
}

void
evm_szofva(void)
{
    r0.t = t_int;
    r0.v.i = thread_self->vcount;
}

static eint32_t
get_offset_safe(void)
{
    eint32_t	offset;
    switch (r0.t) {
	case t_void:
	    offset = 0;
	    break;
	case t_int:
	    if ((euint_t)r0.v.i > most_positive_fix32)
		offset = -1;
	    else
		offset = r0.v.i;
	    break;
	case t_float:
	    if (r0.v.d >= 0 && r0.v.d <= most_positive_fix32)
		offset = r0.v.d;
	    else
		offset = -1;
	    break;
	case t_mpz:		case t_shz:		case t_rgz:
	    offset = -1;
	    break;
	case t_mpq:		case t_shq:		case t_rgq:
	    mpz_set_q(thr_zr, r0.v.mpq);
	    if (mpz_fits_sint_p(thr_zr))
		offset = mpz_get_si(thr_zr);
	    else
		offset = -1;
	    break;
	case t_mpr:		case t_shr:		case t_rgr:
	    if (mpfr_fits_sint_p(r0.v.mpr, GMP_RNDZ))
		offset = empr_get_i(r0.v.mpr);
	    else
		offset = -1;
	    break;
	default:
	    offset = -1;
	    break;
    }
    return (offset);
}

void
evm_szofdim(void)
{
    eint32_t	offset;
    offset = get_offset_safe();
    r0.t = t_int;
    if (evector_type_p(sp[-1].t) && (euint32_t)offset < sp[-1].v.V->rank)
	r0.v.i = sp[-1].v.V->dims[r0.v.i].dim;
    else
	r0.v.i = 0;
    --sp;
}

void
evm_szofdimi(eint32_t offset)
{
    if (evector_type_p(r0.t) && (euint32_t)offset < r0.v.V->rank) {
	r0.t = t_int;
	r0.v.i = r0.v.V->dims[offset].dim;
    }
    else {
	r0.t = t_int;
	r0.v.i = 0;
    }
}

void
evm_tpof(void)
{
    eint32_t	type;
    switch (type = r0.t) {
	case t_void:		case t_int:		case t_float:
	case t_mpz:		case t_mpq:		case t_mpr:
	case t_cdd:		case t_cqq:		case t_mpc:
	    break;
	case t_shz:		case t_rgz:
	    type = t_mpz;
	    break;
	case t_shq:		case t_rgq:
	    type = t_mpq;
	    break;
	case t_shr:		case t_rgr:
	    type = t_mpr;
	    break;
	case t_sqq:		case t_rqq:
	    type = t_cqq;
	    break;
	case t_shc:		case t_rgc:
	    type = t_mpc;
	    break;
	case t_localref:	case t_t_localref:
	    {
		evalue_t	*v = r0.v.loc->thread->ess + r0.v.loc->offset;
		if (v >= r0.v.loc->thread->esp || (v->t == t_void && v->v.o))
		    type = t_pointer|t_void;
		else
		    type = t_pointer|(v->t & ~t_const);
	    }
	    break;
	case t_anonref:		case t_globalref:
	    type = t_pointer|(eobject_type(*r0.v.v) & ~t_const);
	    break;
	case t_stackref:	case t_t_stackref:
	    r0.v.i = t_pointer|(r0.v.ref->t & ~t_const);
	    break;
	default:
	    if ((type & (t_pointer|t_vector)) == (t_pointer|t_vector)) {
		/* check if it is a pointer to vector of vectors */
		r0.v.o = r0.v.V->v.u8;
		type = t_pointer|(eobject_type(r0.v.V->v.u8) & ~(t_resize|t_const));
	    }
	    else
		type &= ~t_const;
	    break;
    }
    r0.t = t_int;
    r0.v.i = type;
}

void
evm_subtpof(void)
{
    eint32_t	result;
    result = 0;
    if (r0.t < ets_idx && r0.t > elast_basic_type && sp[-1].t == t_int) {
	eint32_t	base;
	base = sp[-1].v.i;
	if (base < ets_idx && base > elast_basic_type) {
	    if (r0.t != base) {
		eint32_t	type;
		type = r0.t;
		do {
		    if ((type = ets[type].super) == base) {
			result = 1;
			break;
		    }
		} while (type != t_void);
	    }
	    else
		result = 1;
	}
    }
    r0.t = t_int;
    r0.v.i = result;
    --sp;
}

void
evm_rankof(void)
{
    eint32_t	rank;
    if (likely(evector_type_p(r0.t)))
	rank = r0.v.V->rank;
    else
	rank = 0;
    r0.t = t_int;
    r0.v.i = rank;
}

void
evm_vas(eint32_t offset)
{
    eobject_t	fixnum;
    v_check(1);
    fixnum = efixnum(thread_self->vcount);
    thread_self->vcount = offset;
    v_push(fixnum);
}

void
evm_val(eint32_t offset)
{
    eobject_t	fixnum;
    fixnum = v_pop();
    thread_self->vcount = eget_fixnum(fixnum);
    sp -= offset;
}

void
evm_lva(eint32_t length)
{
    eint32_t	offset;
    offset = get_offset();
    if (unlikely((euint32_t)offset >= thread_self->vcount))
	evm_raise(except_out_of_bounds);
    load_value(bp + length - offset);
}

void
evm_lvai(eint32_t length, eint32_t offset)
{
    if (unlikely((euint32_t)offset >= thread_self->vcount))
	evm_raise(except_out_of_bounds);
    load_value(bp + length - offset);
}

void
evm_sva(eint32_t length)
{
    eint32_t	offset;
    offset = get_offset_value(sp - 1);
    if (unlikely((euint32_t)offset >= thread_self->vcount))
	evm_raise(except_out_of_bounds);
    evm_store_value(bp + length - offset);
    --sp;
}

void
evm_svai(eint32_t length, eint32_t offset)
{
    if (unlikely((euint32_t)offset >= thread_self->vcount))
	evm_raise(except_out_of_bounds);
    evm_store_value(bp + length - offset);
}

void
evm_pva(eint32_t length)
{
    eint32_t	offset;
    offset = get_offset();
    if (unlikely((euint32_t)offset >= thread_self->vcount))
	evm_raise(except_out_of_bounds);
    r0.t = t_stackref;
    r0.v.ref = bp + length - offset;
}

void
evm_try(eobject_t ip)
{
    sp += 4;
    /* previous tryoff value */
    sp[-4].t = t_int;
    sp[-4].v.i = thread_self->tryoff;
    /* new tryoff value */
    thread_self->tryoff = sp - ss - 4;
    /* per thread gc protected objects */
    sp[-3].t = t_int;
    sp[-3].v.i = thread_self->gsi;
    /* current ebp offset */
    sp[-2].t = t_int;
    sp[-2].v.i = bp - ss;
    /* catch target */
    sp[-1].t = t_void;
    sp[-1].v.o = ip;
}

void
evm_catch(void)
{
    evalue_t	*v;
#if DEBUG
    if (unlikely(thread_self->tryoff < 0))
	evm_raise(except_unhandled_exception);
#endif
    /* restore state */
    v = ss + thread_self->tryoff;
    thread_self->tryoff = v[0].v.i;
    thread_self->gsi = v[1].v.i;
    bp = ss + v[2].v.i;
    sp = v;
    /* exception object is in r0 */
    switch (r0.t) {
	case t_void:
	    evalue.t = t_void;
	    evalue.v.o = null;
	    break;
	case t_int:
	    evalue.t = t_int;
	    evalue.v.i = r0.v.i;
	    break;
	case t_float:
	    evalue.t = t_float;
	    evalue.v.d = r0.v.d;
	    break;
	case t_shz:		case t_rgz:
	    if (evalue.t == t_mpz)
		empz_set(evalue.v.mpz, r0.v.mpz);
	    else {
		enew_mpz(&obj, r0.v.mpz);
		r0.v.o = evalue.v.o = obj;
		r0.t = evalue.t = t_mpz;
	    }
	    break;
	case t_shq:		case t_rgq:
	    if (evalue.t == t_mpq)
		empq_set(evalue.v.mpq, r0.v.mpq);
	    else {
		enew_mpq(&obj, r0.v.mpq);
		r0.v.o = evalue.v.o = obj;
		r0.t = evalue.t = t_mpq;
	    }
	    break;
	case t_shr:		case t_rgr:
	    if (evalue.t == t_mpr)
		empr_set(evalue.v.mpr, r0.v.mpr);
	    else {
		enew_mpr(&obj, r0.v.mpr);
		r0.v.o = evalue.v.o = obj;
		r0.t = evalue.t = t_mpr;
	    }
	    break;
	case t_cdd:
	    evalue.t = t_cdd;
	    evalue.v.cdd = r0.v.cdd;
	    break;
	case t_sqq:		case t_rqq:
	    if (evalue.t == t_cqq)
		ecqq_set(evalue.v.cqq, r0.v.cqq);
	    else {
		enew_cqq(&obj, r0.v.cqq);
		r0.v.o = evalue.v.o = obj;
		r0.t = evalue.t = t_cqq;
	    }
	    break;
	case t_shc:		case t_rgc:
	    if (evalue.t == t_mpc)
		empc_set(evalue.v.mpc, r0.v.mpc);
	    else {
		enew_mpc(&obj, r0.v.mpc);
		r0.v.o = evalue.v.o = obj;
		r0.t = evalue.t = t_mpc;
	    }
	    break;
	case t_localref:	case t_t_localref:
	    if (r0.v.loc->thread == thread_self &&
		r0.v.loc->offset >= sp - ss) {
		/* if throwing a pointer to a now unbound local variable */
		r0.v.o = evalue.v.o = null;
		r0.t = evalue.t = t_void;
	    }
	    else {
		evalue.v.o = r0.v.o;
		evalue.t = r0.t;
	    }
	    break;
	case t_stackref:
	    if (r0.v.ref >= sp) {
		r0.v.o = evalue.v.o = null;
		r0.t = evalue.t = t_void;
	    }
	    else {
		enew_localref(&obj, r0.v.ref - ss);
		r0.v.o = evalue.v.o = obj;
		r0.t = evalue.t = t_localref;
	    }
	    break;
	case t_t_stackref:
	    if (r0.v.ref >= sp) {
		r0.v.o = evalue.v.o = null;
		r0.t = evalue.t = t_void;
	    }
	    else {
		enew_t_localref(&obj, r0.v.ref - ss);
		r0.v.o = evalue.v.o = obj;
		r0.t = evalue.t = t_t_localref;
	    }
	    break;
	default:
	    evalue.v.o = r0.v.o;
	    evalue.t = r0.t;
	    break;
    }
}

eobject_t
evm_throw(eint32_t reload)
{
    eobject_t	ip;
    if (thread_self->tryoff < 0)
	evm_raise(except_unhandled_exception);
    ip = ss[thread_self->tryoff + 3].v.o;
    if (reload) {
	switch (evalue.t) {
	    case t_void:
		r0.t = t_void;
		r0.v.o = null;
		break;
	    case t_int:
		r0.t = t_int;
		r0.v.i = evalue.v.i;
		break;
	    case t_float:
		r0.t = t_float;
		r0.v.d = evalue.v.d;
		break;
	    case t_globalref:
		r0.t = t_globalref;
		r0.v.o = evalue.v.o;
		break;
	    case t_cdd:
		r0.t = t_cdd;
		r0.v.cdd = evalue.v.cdd;
		break;
	    case t_localref:	case t_t_localref:
		if (r0.v.loc->thread == thread_self &&
		    r0.v.loc->offset >= sp - ss) {
		    /* if throwing a pointer to a, now unbound local variable */
		    r0.t = t_void;
		    r0.v.o = null;
		}
		else {
		    r0.v.o = evalue.v.o;
		    r0.t = evalue.t;
		}
		break;
	    default:
		r0.v.o = obj = evalue.v.o;
		r0.t = evalue.t;
		break;
	}
    }
    else {
	switch (r0.t) {
	    case t_void:	case t_int:		case t_float:
	    case t_shz:		case t_rgz:		case t_shq:
	    case t_rgq:		case t_shr:		case t_rgr:
	    case t_cdd:		case t_sqq:		case t_rqq:
	    case t_shc:		case t_rgc:		case t_globalref:
		break;
	    case t_mpz:
		empz_set(thr_zr, r0.v.mpz);
		set_rz();
		break;
	    case t_mpq:
		empq_set(thr_qr, r0.v.mpq);
		set_rq();
		break;
	    case t_mpr:
		empr_set(thr_rr, r0.v.mpr);
		set_rr();
		break;
	    case t_cqq:
		ecqq_set(thr_qq, r0.v.cqq);
		set_rqq();
		break;
	    case t_mpc:
		empc_set(thr_c, r0.v.mpc);
		set_rrr();
		break;
	    default:
		break;
	}
    }
    return (ip);
}

void
evm_unwind(void)
{
    evalue_t	*v;
    v = ss + thread_self->tryoff;
    thread_self->tryoff = v[0].v.i;
    sp = v;
}

void
evm_exit(void)
{
#if HAVE_THREAD
    /* lock thread linked lists */
    ethreads_lock();
    thread_self->running = 0;
    if (thread_self == tmain) {
	/* tmain is not reassigned */
	emutex_lock(&count_mutex);
	ethreads_unlock();
	while (tmain->next != tmain)
	    /* wait for children threads to exit */
	    pthread_cond_wait(&count_cond, &count_mutex);
	emutex_unlock(&count_mutex);
    }
    else {
	ethread_t	*ptr;
	/* remove from thread circular list */
	for (ptr = thread_self->next; ptr->next != thread_self; ptr = ptr->next)
	    ;
	ptr->next = thread_self->next;
	emutex_lock(&count_mutex);
	ethreads_unlock();
	if (ptr->next == ptr)
	    pthread_cond_signal(&count_cond);
	emutex_unlock(&count_mutex);
	/* free mpfr per thread cache data */
	mpfr_free_cache();
	pthread_exit(null);
    }
#endif
}

void
evm_setup(eint32_t offset, eint32_t type)
{
    switch (type) {
	case t_int8:	case t_uint8:
	    enew_object(eds + offset, type, 1);
	    break;
	case t_int16:	case t_uint16:
	    enew_object(eds + offset, type, 2);
	    break;
	case t_int32:	case t_uint32:
	    enew_object(eds + offset, type, 4);
	    break;
	case t_int:	case t_uint:
	    enew_object(eds + offset, type, 8);
	    break;
	case t_float32:
	    enew_object(eds + offset, type, 4);
	    *(efloat32_t *)eds[offset] = 0.0;
	    break;
	case t_float:
	    enew_object(eds + offset, type, 8);
	    *(efloat_t *)eds[offset] = 0.0;
	    break;
	default:
	    break;
    }
}

void
evm_intp_0(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 0;
	    break;
	default:
	    evm_raise(except_not_an_integer);
    }
}

void
evm_intp_v(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_mpz:		case t_shz:		case t_rgz:
	    break;
	default:
	    evm_raise(except_not_an_integer);
    }
}

void
evm_intp_n1(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = -1;
	    break;
	default:
	    evm_raise(except_not_an_integer);
    }
}

void
evm_realp_v(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_float:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_mpr:		case t_shr:		case t_rgr:
	    break;
	default:
	    evm_raise(except_not_a_real_number);
    }
}

void
evm_nump_0(void)
{
    switch (r0.t) {
	case t_void:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_cqq:		case t_sqq:		case t_rqq:
	    r0.t = t_int;
	case t_int:
	    r0.v.i = 0;
	    break;
	case t_cdd:
	    r0.t = t_float;
	case t_float:
	    r0.v.d = 0.0;
	    break;
	case t_mpr:		case t_shr:
	case t_mpc:		case t_shc:		case t_rgc:
	    mpfr_set_ui(thr_rr, 0, thr_rnd);
	    set_rr();
	    break;
	case t_rgr:
	    mpfr_set_ui(thr_rr, 0, thr_rnd);
	    break;
	default:
	    evm_raise(except_not_a_number);
    }
}

void
evm_nump_v(void)
{
    switch (r0.t) {
	case t_void:
	    r0.t = t_int;
	    r0.v.i = 0;
	    break;
	case t_int:
	case t_float:
	case t_mpz:		case t_shz:		case t_rgz:
	case t_mpq:		case t_shq:		case t_rgq:
	case t_mpr:		case t_shr:		case t_rgr:
	case t_cdd:
	case t_cqq:		case t_sqq:		case t_rqq:
	case t_mpc:		case t_shc:		case t_rgc:
	    break;
	default:
	    if (!evector_type_p(r0.t))
		evm_raise(except_not_a_number);
    }
}
